子線程中開啓一個主線程去獲取某些數據,此時子線程要處理等待狀態,獲取成功以後繼續執行子線程中以後的代碼.java
final Object obj = new Object();
new Thread(){
@Override
public void run() {
super.run();
//經過Handler建立一個主線程.
new Handler(getMainLooper()).post(new Runnable() {
@Override
public void run() {
synchronized (obj) {
//模擬主線程耗時操做
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
str = "WangChao";
Log.e("CHAO", "run 2" + str);
obj.notify();
}
}
});
Log.e("CHAO","run 1");
synchronized (obj) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//子線程須要主線程的返回參數
if (str != null) {
Log.e("CHAO", "run 3" + str);
}
}
}
}.start();複製代碼
運行可知先運行的是run 1 ,以後是主線程中的run 2 ,而後是子線程中的 run 3.這樣就能夠達到咱們想要的結果.運行結果以下:com.example.wang.threaddemo E/CHAO: run 1
com.example.wang.threaddemo E/CHAO: run 2WangChao
com.example.wang.threaddemo E/CHAO: run 3WangChao複製代碼
synchronized關鍵字的用法
被synchronized修飾的方法稱爲同步方法,默認的鎖是當前對象.所謂同步方法是若是有一個線程正在訪問該方法的時候,其餘的方法調用到該方法的時候將進入等待的狀態.當有多個同步方法的時候,一旦一個線程調用了其中的一個同步方法,便對當前對象加鎖,其餘的線程調用擁有同對象鎖的其它同步方法時會處於等待的狀態,等以前的線程釋放掉對象鎖以後繼續執行.
1.去修飾方法 : 對象鎖默認是當前對象 this .bash
public synchronized void method2(){
Log.e("CHAO", "method2: " + Thread.currentThread().getName());
}複製代碼
還能夠這樣寫:多線程
public void method2(){
synchronized (this) {
Log.e("CHAO", "method2: " + Thread.currentThread().getName());
}
}複製代碼
2.同步語句塊 : 能夠本身去設置加鎖的對象.ide
synchronized (obj) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
str = "WangChao";
Log.e("CHAO", "2" + str);
obj.notify();
}複製代碼
這裏須要注意的是synchronized (obj) 裏面的參數,也就是要給那個對象加鎖.這個對象必須是惟一的切多個線程都能拿到這個對象.(再使用Stirng最爲對象鎖的時候必定要注意String的從新賦值,一旦賦值改對象就改變了再也不是咱們以前加鎖的對象),一般能夠本身去建立一個final 的 Object類去加鎖,也可使用this,Class對象等.oop
3.同步靜態方法啊: 加鎖對象是當前的Class對象.post
public static synchronized void method1(){
int count = 0;
for (int i = 0; i < 120000; i++) {
count++;
}
Log.e("CHAO", "method1: " + Thread.currentThread().getName());
}複製代碼
同不得靜態方法再多線程中的調用和非靜態的是一致的.ui
wait()
首先wait()是屬於Object類的方法,從源碼給出的解釋來看,wait()方法能夠作到以下幾點:
(1)首先,調用了wait()以後會引發當前線程處於等待狀狀態。
(2)其次,每一個線程必須持有該對象的monitor(監視)。若是在當前線程中調 用wait()方法以後,該線程就會釋放monitor的持有對象並讓本身處於等 待狀態。
(3)若是想喚醒一個正在等待的線程,那麼須要開啓一個線程經過notify()或者notifyAll()方法去通知正在等待的線程獲取monitor對象。如此,該線程便可打破等待的狀態繼續執行代碼.this
注意: wait()方法要使用在synchronized修飾的方法裏面要否則會報異常,而且是synchronized()加鎖的那個對象調用該方法.異常以下:spa
java.lang.IllegalMonitorStateException: object not locked by thread before wait()複製代碼
notify() , nitifyAll()
notify()是屬於Object類的方法.notify喚醒一個在這個對象上等待的線程監控。若是有任何線程在等待這個對象,其中一個線程被選擇被喚醒。這個選擇是任意的,而且發生在執行的自由裁量。一個線程在一個對象上等待經過調用wait()等方法來監視。nitifyAll喚醒全部的再等待中的線程.線程
注意:nitify喚醒的線程會在該線程的wiat以後繼續執行,特別要注意的是調用wiat的同步語句塊的對象鎖要和nitify的同步語句塊的對象鎖是同一個,不然的話你是喚醒不了wait狀態的.
final Object obj = new Object();
new Thread(){
@Override
public void run() {
super.run();
new Handler(getMainLooper()).post(new Runnable() {
@Override
public void run() {
//注意這個加鎖對象
synchronized (obj) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
str = "WangChao";
Log.e("CHAO", "2" + str);
//注意喚醒方法的調用者
obj.notify();
}
}
});
Log.e("CHAO","run"+1);
//注意這個加鎖對象
synchronized (obj) {
try {
//注意等待方法的調用者
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (str != null) {
Log.e("CHAO", "3" + str);
}
}
}
}.start();複製代碼
(1)在線程的運行過程當中,調用該線程持有monitor對象的wait()方法時,該線程首先會進入等待狀態,並將本身持有的monitor對象釋放。
(2)若是一個線程正處於等待狀態時,那麼喚醒它的辦法就是開啓一個新的線程,經過notify()或者notifyAll()的方式去喚醒。固然,須要注意的一點就是,必須是同一個monitor對象。
(3)sleep()方法雖然會使線程中斷,可是不會將本身的monitor對象釋放,在中斷結束後,依然可以保持代碼繼續執行。
歡迎你們的點評和補充,喜歡的話就給個贊👍支持下吧~