線程小知識總結【線程創建、線程優先級、線程安全】

進程歷史

在這裏插入圖片描述在這裏插入圖片描述

疑問:進程和線程的區別
答:進程是資源分配的最小單位,手握操作系統給他分配的monney,是分包商
線程是CPU調度的最小單位,不持有資源,去請求進程的資源,並消耗資源
進程是搶佔處理機的調度單位,擁有內存中虛擬空間
線程屬於某個進程,佔用該進程的地址空間
疑問:什麼是資源?
答:資源信息包括程序段、數據集,所有與進程相關的資源,都被記錄在PCB中。
疑問:線程擁有什麼?
答:堆棧寄存器、程序計數器和TCB
Java採用單線程編程模型,程序主動創建主線程。
疑問:什麼是單線程編程模型
答:不特殊指定,默認是主線程。有耗時操作,放在子線程裏。
主線程往往最後執行完畢,最後死掉。
疑問:既然是單線程模型,那JVM是否是單線程模型?
答:JVM實例創建之時,有多線程,如GC、

創建線程

方式1

public class CreateThread {
    public static void main(String[] args) {
        Thread t1 = new Thread();
        Thread t2 = new Thread() {
            @Override
            public void run() {
                System.out.println("==========");
            }
        };
        t1.start();
        t2.start();
        System.out.println(t1.getName());
        System.out.println(t2.getName());

        Thread t3 = new Thread("MyName");
        Thread t4 = new Thread(() -> {
            System.out.println("Runnable...");
        });

        System.out.println(t3.getName());
        System.out.println(t4.getName());

        Thread t5 = new Thread(() -> {
            System.out.println("Runnable..." + Thread.currentThread().getName());
        }, "RunnableThread");

        t5.start();
    }
}

方式2

public class CreateThread2 {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t.start();
//        System.out.println(t.getThreadGroup());
//        System.out.println(Thread.currentThread().getName());
        ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
//        System.out.println(threadGroup.getName());

        System.out.println(threadGroup.activeCount());

        Thread[] threads = new Thread[threadGroup.activeCount()];
        threadGroup.enumerate(threads);

        Arrays.asList(threads).forEach(System.out::println);
    }
}

方式3 主線程

public class CreateThread3 {

    private int i = 0;

    private byte[] bytes = new byte[1024];

    private static int counter = 0;

    //JVM will create a thread named "main"
    public static void main(String[] args) {
        //create a JVM stack
        try {
            add(0);
        } catch (Error e) {
            e.printStackTrace();
            System.out.println(counter);
        }
    }

    private static void add(int i) {
        ++counter;
        add(i + 1);
    }
}

方式4

public class CreateThread4 {

    private static int counter = 1;

    public static void main(String[] args) {

        Thread t1 = new Thread(null, new Runnable() {
            @Override
            public void run() {
                try {
                    add(1);
                } catch (Error e) {
                    System.out.println(counter);
                }
            }

            private void add(int i) {
                counter++;
                add(i + 1);
            }
        }, "Test", 1 << 24);
        t1.start();
    }
}

方式5

public class CreateThread5 {

    private static int counter = 1;

    public static void main(String[] args) {

        try {
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                counter++;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            add(1);
                        } catch (Error e) {
//                            System.out.println(counter);
                        }
                    }

                    private void add(int i) {

                        add(i + 1);
                    }
                }).start();
            }
        } catch (Error e) {
            counter++;
        }
        System.out.println("Total created thread nums=>" + counter);
    }
}

Thread的start與run區別

start會創建新的子線程,並啓動
run只是Trhead的普通方法調用,仍然在主線程執行。

Thread與Runnable區別

線程設置Daemon、優先級、ID

Daemon線程

public class DaemonThread {

    public static void main(String[] args) throws InterruptedException {

        Thread t = new Thread() {

            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " running");
                    Thread.sleep(100000);
                    System.out.println(Thread.currentThread().getName() + " done.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }; //new
        t.start();
        t.setDaemon(true);
        //runnable  ->running| ->dead| ->blocked


        Thread.sleep(5_000);   //JDK1.7
        System.out.println(Thread.currentThread().getName());
    }
}

/**
 * A<---------------------------------->B
 *  ->daemonThread(health check)
 * */

Daemon線程2

public class DaemonThread2 {
    public static void main(String[] args) {

        Thread t = new Thread(() -> {
            Thread innerThread = new Thread(() -> {
                try {
                    while (true) {
                        System.out.println("Do some thing for health check.");
                        Thread.sleep(1_000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

            //innerThread.setDaemon(true);
            innerThread.start();

            try {
                Thread.sleep(1_000);
                System.out.println("T thread finish done.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        //t.setDaemon(true);
        t.start();


    }
}

線程ID、優先級

普通場景

public class ThreadSimpleAPI {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            Optional.of("Hello").ifPresent(System.out::println);
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1");

        t.start();
        Optional.of(t.getName()).ifPresent(System.out::println);
        Optional.of(t.getId()).ifPresent(System.out::println);
        Optional.of(t.getPriority()).ifPresent(System.out::println);
    }
}

實際場景

public class ThreadSimpleAPI2 {

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
            }
        });
        t1.setPriority(Thread.MAX_PRIORITY);

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
            }
        });

        t2.setPriority(Thread.NORM_PRIORITY);

        Thread t3 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
            }
        });

        t3.setPriority(Thread.MIN_PRIORITY);

        t1.start();
        t2.start();
        t3.start();
    }
}

工具jconsole

線程中斷1

public class ThreadClose {
    private static class Worker extends Thread {

        @Override
        public void run() {
            while (true) {
                if (Thread.interrupted())
                    break;
            }
            //-------------
            //-------------
            //-------------
        }
    }

    public static void main(String[] args) {
        Worker worker = new Worker();
        worker.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        worker.interrupt();
    }
}

線程中斷2

public class ThreadService {

    private Thread executeThread;

    private boolean finished = false;

    public void execute(Runnable task) {
        executeThread = new Thread() {
            @Override
            public void run() {
                Thread runner = new Thread(task);
                runner.setDaemon(true);

                runner.start();
                try {
                    runner.join();
                    finished = true;
                } catch (InterruptedException e) {
                    //e.printStackTrace();
                }
            }
        };

        executeThread.start();
    }

    public void shutdown(long mills) {
        long currentTime = System.currentTimeMillis();
        while (!finished) {
            if ((System.currentTimeMillis() - currentTime) >= mills) {
                System.out.println("任務超時,需要結束他!");
                executeThread.interrupt();
                break;
            }

            try {
                executeThread.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("執行線程被打斷!");
                break;
            }
        }

        finished = false;
    }
}

JMM內存模型、線程安全

什麼是Java內存模型中的happens-before
Java內存模型JMM
Java內存模型(即JavaMemoryModel,簡MM)本身是一種抽象的念,
並不真實存在它描述的是一組規則或規範,通過這組規範定義了程序中各個
變量(包括實例字段,靜態字段和構成數組對象的元素)的訪問方式·

在這裏插入圖片描述
JMM中的主內存
-存儲」ava實例對象
-聲包括成員變量、類信息、常量、靜態變量等
-聲屬於數據共享的區域,多線程併發操作時會引發線程安全問題

JMM與Java內存區域劃分是不同的概念層冫欠
-jMM描述的是一組規則,圍繞原子性,有序性、可見性展開
-相似點:存在共享區域和私有區域

jMM中的主內存和工作內存
主內存與工亻乍內存的存儲類型以及操亻乍方式歸納
-方法裏的基本數據舉型本地變量將直接存儲在工作內存的棧幀結構
-引用類型的本地變量:引用存儲在工作內存中,實例存儲在主內存
-成員變量、static變量、類信息均會被存儲在主內存中
-主內存共享的方式是線程各拷貝刪分數據到工作內存,操作完成
後刷新回主內存
在這裏插入圖片描述

volatile和synchronized的區別

demo實力:

volatile和synchronized的區別
1.vo丨ati|e本質是在告訴」VM當前變量在寄存器(工作內存)中的值是不確
定的,需要從主存中讀取,synchronized則是鎖定當前變量,只有當前
線程可以訪問該變量,其他線程被阻塞住直到該線程完成變量操亻乍爲止
2,vo|ati|e僅能使用在變量級別;synchronized則可以使用在變量、方法
和類級別
3.v引ati|e僅能實現變量的修改可見性,不能保證原子性而
syn(hronized則可以保證變量修改的可見性和原子性
4,vo丨ati|e不會造成線程的阻塞,syn(hronized可能會造成線程的阻塞
5.volati|e標記的變量不會被編譯器優化,synchronizedfii己的變量可以
被編譯器優化

synchronized和lock區別

1)Lock是一個接口,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;

2)synchronized在發生異常時,會自動釋放線程佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;

3)Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;

4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。

5)Lock可以提高多個線程進行讀操作的效率。

在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。

synchronized與線程安全

恰當的合理的上鎖,是線程安全的關鍵

synchronized安全問題的主要誘因
聲存在共享數據他稱臨界資源)
龍存在多條線程共同操作這些共享數據
解決問題的根本方法
同一時刻有且只有一個線程在操作共享數據其他線程必須等到該線
程處理完數據後再對共享數據進行操作

synchronized互斥鎖(原子性)的特性
互斥性·即在同一時間只允許一個線程持有某個對象鎖,通過這種特性
來實現多線程的協調機制,這樣在同一時間只有一個線不寸需要同步的
代碼塊(複合操作)進行訪問。互斥性也稱爲操作的原子性。
可見性:必須確保在鎖被釋放之前,對共享變量所做的修改,對於隨後
獲得該鎖的另一個線程是可見的(即在獲得鎖時應獲得最新共享變量的
值),否貝刂另一個線程可能是在本地緩存的某個副本上繼續操作,從而引起不一致。
synchronized鎖的不是代碼,鎖的都是對象

synchronized
根據獲取的鎖的分類·獲取對象鎖和獲取類鎖
獲取對象鎖的兩種用法
1.同步代碼塊(synchronized(this),synchronized(類實例對
象)),鎖是小括號0中的實例對象。
2,同步非靜態方法(synchronizedmethod)鎖是當前對象的實
例對象。

在這裏插入圖片描述
疑問:waite與sleep的區別
疑問:線程的生命週期

參考

volatile和synchronized的區別

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章