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存入值,但每個執行緒還是能取出屬於自己的資料。