如何讓 10 個線程按照順序打印 0123456789?
-
設定一個 orderNum,每個線程執行結束之後,更新 orderNum,指明下一個要執行的線程。並且喚醒所有的等待線程。
-
在每一個線程的開始,要 while 判斷 orderNum 是否等於自己的要求值!!不是,則 wait,是則執行本線程。
while(順序不匹配){
wait
}
update orderNum
import java.util.ArrayList;
import java.util.List;
public class thredSortedPrint {
public static void main(String[] args) {
//創建10個線程
List<myThread> list = new ArrayList<myThread>();
for(int i=10;i>0;i--){
myThread thread = new myThread(i);
thread.start();
}
}
//創建一個內部靜態類
static class myThread extends Thread{
public int Num;
static int orderNum = 1;
//創建一個靜態的object類作爲共同的互斥鎖資源
static final Object object = new Object();
public myThread (int num){
this.Num = num;
};
@Override
public void run(){
synchronized (object){
//順序不匹配則等待,並讓出鎖資源
while(Num != orderNum){
try {
System.out.println(Thread.currentThread().getName()+":wait");
//鎖是object,用object.wait(),當前線程被阻塞,進入等待隊列,同時釋放互斥鎖object
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//匹配則輸出打印,更新orderNum,並通知所有線程。
System.out.println(Thread.currentThread().getName()+":"+Num);
orderNum++;
//通知互斥鎖的等待隊列
object.notifyAll();
}
}
}
}
運行並查看結果,如下。
Thread-0:wait
Thread-1:wait
Thread-3:wait
Thread-4:wait
Thread-7:wait
Thread-8:wait
Thread-2:wait
Thread-6:wait
Thread-5:wait
Thread-9:1
Thread-5:wait
Thread-6:wait
Thread-2:wait
Thread-8:2
Thread-7:3
Thread-4:wait
Thread-3:wait
Thread-1:wait
Thread-0:wait
Thread-2:wait
Thread-6:4
Thread-5:5
Thread-2:wait
Thread-0:wait
Thread-1:wait
Thread-3:wait
Thread-4:6
Thread-3:7
Thread-1:wait
Thread-0:wait
Thread-2:8
Thread-0:wait
Thread-1:9
Thread-0:10
補充:如果通知等待隊列的語句改成 object.notify(),可能會導致所有等待的線程都處於等待狀態,應該被喚醒的線程沒有機會再被喚醒。如下,啓動的線程爭搶CPU資源,如果打印順序剛好匹配,則執行並隨機通知一個處於等待隊列的線程。但是若所有線程都啓動了,除去已執行完的線程,剩下的都在隊列裏,這時候Thread-8執行完後隨機通知,被通知到恰好是Thread-3,而此時應該被通知的是Thread-7。Thread-3因打印順序不匹配,進入等待隊列。這時候剩餘所有線程都在隊列裏,也就沒有線程會被通知並執行了,形成了活鎖。
//通知互斥鎖的等待隊列
object.notify();
Thread-2:wait
Thread-3:wait
Thread-7:wait
Thread-6:wait
Thread-1:wait
Thread-5:wait
Thread-9:1
Thread-2:wait
Thread-0:wait
Thread-4:wait
Thread-8:2
Thread-3:wait
運用jconsole工具查看線程執行情況 : https://blog.csdn.net/Henry_Lin_Wind/article/details/103408654
剩餘的線程全部在等待,但是並沒有死鎖,所以要慎重使用notify()。