java多執行緒順序列印ABCD四個字母
阿新 • • 發佈:2019-01-09
實現的java通4個執行緒順序列印ABCD四個字母,第一個執行緒列印A,第二個執行緒列印B,第三個執行緒列印C,第四個執行緒列印D,每個執行緒列印10次
我說一下我的思路,因為都是列印,所以定義一個用以列印的方法,因為需要執行緒同步,控制什麼時候哪些執行緒能執行那些執行緒休眠,所以用synchronized同步塊。
下面一些關於同步的知識:
- 每一個物件都有一個互斥的鎖標記和一個鎖池
- 關鍵字:synchronized 執行緒在同步程式碼中必須採用序列訪問
- synchronized修飾的程式碼塊:對括號內的物件object加鎖,只有拿到物件鎖標記的執行緒才能進入改程式碼塊。
- 同步依賴物件鎖,鎖相同,同步語句序列,鎖物件不同,同步語句並行
- 呼叫wait():交出鎖和CPU佔用,進入執行緒呼叫wait物件的等待待池(wait pool)
- 呼叫notify:將從物件的等待池中移走一個執行緒並放入鎖池中,直接可以獲得物件鎖標記
synchronized(a){
synchronized(b){
//列印
}
}
B執行緒需要獲得b和c的鎖標記才能執行列印:
synchronized(b){
synchronized(c){
//列印
}
}
C執行緒需要獲得c和d的鎖標記才能執行列印:
synchronized(c){ synchronized(d){ //列印 } }
D執行緒需要獲得d和a的鎖標記才能執行列印:
synchronized(d){
synchronized(a){
//列印
}
}
剛開始a、b、c、d的等待池中都沒有ABCD四個執行緒,所以ABCD都有機會執行列印方法裡打同步程式碼 A執行緒執行列印完畢呼叫b.notify()從b的等待池的中移走一個執行緒,a.wait()進入a的等待池(a物件等待池:A執行緒)
B執行緒執行列印完畢呼叫c.notify()從b的等待池的中移走一個執行緒,b.wait()進入a的等待池(b物件等待池:B執行緒)
C執行緒執行列印完畢呼叫d.notify()從b的等待池的中移走一個執行緒,c.wait()進入a的等待池(c物件等待池:C執行緒)
D執行緒執行列印完畢呼叫a.notify()從b的等待池的中移走一個執行緒,d.wait()進入a的等待池(d物件等待池:D執行緒,a物件等待池:沒有A執行緒)
D執行緒執行完後a和b執行緒池裡都沒有A執行緒,而BCD執行緒都不能同時獲取它們執行列印所需要的兩個物件鎖標記,所以此時只有A執行緒能執行列印, A執行緒第二次列印往後把b物件等待池的一個執行緒移走,因為b的等待池只有B執行緒,所以B執行緒被移走放入鎖池,此時只有B執行緒能執行列印,以此類推,B列印後只能執行C,C列印後只能執行D,D列印後只能執行A...
因為剛開始一起啟用四個執行緒後不知道哪個執行緒會先執行列印,所以需要控制執行緒啟動後的首次執行順,我的做法是在建立執行緒的類里加兩個靜態整型變數newIndex和runIndex,每當建立執行緒的物件是就把當前執行緒的Id設為newIndex的值,然後newIndex加1,每個執行緒首次執行列印後都把runIndex加1,當執行緒執行到synchronized裡先判斷當前執行緒的id是否大於runIndex,如果大於說明這個執行緒是首次執行且還不應該到它執行列印,所以把它在外層synchronized的物件上休眠等待它上一個執行緒執行答應後喚醒它。
每次一個執行緒列印完後就休眠了,為了控制每個執行緒列印完了最後一次直接結束而不是進入休眠所以在列印後需要判斷一下是否當前執行緒已經完成了所以列印次數。
下面是一種實現的程式碼:
public class ThreadSortPrintABCD implements Runnable {
private static int newIndex = 0;
private static int runIndex = 0;
private int id;
private boolean isFirstRun;
private String name;
private Object self;
private Object next;
private ThreadSortPrintABCD(String name, Object self, Object next) {
id = newIndex++;
this.name = name;
this.self = self;
this.next = next;
}
@Override
public void run() {
int count = 10;
while (count > 0) {
synchronized (self) {
if(id > runIndex) {
try {
self.wait();
} catch (InterruptedException e) {
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
}
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e1) {
// TODO 自動生成的 catch 塊
e1.printStackTrace();
}
System.out.print(name);
if(!isFirstRun) {
runIndex++;
isFirstRun = true;
}
count--;
synchronized (next) {
next.notify();
}
if(count > 0) {
try {
self.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
Object c = new Object();
Object d = new Object();
ThreadSortPrintABCD pa = new ThreadSortPrintABCD("A", a, b);
ThreadSortPrintABCD pb = new ThreadSortPrintABCD("B", b, c);
ThreadSortPrintABCD pc = new ThreadSortPrintABCD("C", c, d);
ThreadSortPrintABCD pd = new ThreadSortPrintABCD("D", d, a);
new Thread(pa).start();
new Thread(pb).start();
new Thread(pc).start();
new Thread(pd).start();
}
}