1. 程式人生 > >Android小知識-Java多執行緒相關(執行緒間通訊)下篇

Android小知識-Java多執行緒相關(執行緒間通訊)下篇

本平臺的文章更新會有延遲,大家可以關注微信公眾號-顧林海,如果大家想獲取最新教程,請關注微信公眾號,謝謝!

在一種場景中,比如main執行緒建立並啟動了子執行緒,子執行緒需要做耗時操作,如果main執行緒想等子執行緒執行完成之後再結束,由於main執行緒比子執行緒先執行完,因此main執行緒獲取不到子執行緒的值。我們看下面這段程式碼:

public class BeanThread extends Thread{

    @Override
    public void run() {
        super.run();

        try {
            System.out.println("執行一些耗時操作"
); Thread.sleep(3000); System.out.println("經過3秒執行完"); } catch (InterruptedException e) { e.printStackTrace(); } } } 複製程式碼

Client:

public class Client {

    public static void main(String[] args) {
        BeanThread thread=new BeanThread();
        thread.start();
        System.out.println("main執行緒執行完"
); } } 複製程式碼

執行結果:

main執行緒執行完
執行一些耗時操作
經過3秒執行完
複製程式碼

那如何使主執行緒等子執行緒執行完並獲取子執行緒的相關資料?可以使用join()方法,它的作用是使所屬的執行緒物件正常執行run方法中的任務,而使當前執行緒進行無限期的阻塞,等待所屬執行緒銷燬後再繼續執行當前執行緒後面的程式碼。比如:

public class Client {

    public static void main(String[] args) {
        BeanThread thread=new BeanThread();
        thread.start();
        try
{ thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main執行緒執行完"); } } 複製程式碼

再次執行,結果:

執行一些耗時操作
經過3秒執行完
main執行緒執行完
複製程式碼

可以發現執行join()方法後,使當前main執行緒阻塞,等待BeanThread執行緒執行結束後,再執行後面列印語句。

方法join具有使執行緒排隊執行的作用,有些類似同步的執行效果。join與synchronized的區別是:join在內部使用wait()方法進行等待,具有釋放鎖的特點,而synchronized關鍵字使用的“物件監視器”原理作為同步。在join過程中,如果當前執行緒物件被中斷,則當前執行緒出現異常。除了無參join方法外,還有一個有參方法join(long),傳入的引數代表設定等待的時間。

變數值的共享可以使用public static變數的形式,所有的執行緒都使用同一個public static變數。如果想實現每一個執行緒都有自己的共享變數,可以使用ThreadLocal來實現,ThreadLocal主要解決的就是每個執行緒繫結自己的值。可以通過get()方法返回每個執行緒自己的值,預設返回的是null,可以通過繼承ThreadLocal實現initialVaule()方法來設定預設值。

public class DefaultThreadLocal extends ThreadLocal {
    @Override
    protected Object initialValue() {
        return "預設值";
    }
}
複製程式碼

第一個執行緒:

public class ThreadFirst extends Thread {

    @Override
    public void run() {
        super.run();
        try {
            for(int i=0;i<5;i++){
                Client.DEFAULT_THREAD_LOCAL.set("第一個執行緒存入="+i);
                Thread.sleep(1000);
                System.out.println("第一個執行緒取出的值:"+Client.DEFAULT_THREAD_LOCAL.get());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

第二個執行緒:

public class ThreadSecond extends Thread {

    @Override
    public void run() {
        super.run();
        try {
            for(int i=0;i<5;i++){
                Client.DEFAULT_THREAD_LOCAL.set("第二個執行緒存入="+i);
                Thread.sleep(500);
                System.out.println("第二個執行緒取出的值:"+Client.DEFAULT_THREAD_LOCAL.get());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

Client:

public class Client {

    public static DefaultThreadLocal DEFAULT_THREAD_LOCAL=new DefaultThreadLocal();

    public static void main(String[] args) {
       ThreadFirst threadFirst=new ThreadFirst();
       ThreadSecond threadSecond=new ThreadSecond();
       threadFirst.start();
       threadSecond.start();
    }

}
複製程式碼

列印:

第二個執行緒取出的值:第二個執行緒存入=0
第二個執行緒取出的值:第二個執行緒存入=1
第一個執行緒取出的值:第一個執行緒存入=0
第二個執行緒取出的值:第二個執行緒存入=2
第二個執行緒取出的值:第二個執行緒存入=3
第一個執行緒取出的值:第一個執行緒存入=1
第二個執行緒取出的值:第二個執行緒存入=4
第一個執行緒取出的值:第一個執行緒存入=2
第一個執行緒取出的值:第一個執行緒存入=3
第一個執行緒取出的值:第一個執行緒存入=4
複製程式碼

通過列印結果,可以看出兩個執行緒存入的變數具有隔離性,不會互相干擾,兩個執行緒都往Client.DEFAULT_THREAD_LOCAL存入值,但每個執行緒還是能取出屬於自己的資料。


838794-506ddad529df4cd4.webp.jpg