我是小康小白,一個平平無奇的Java小白。熱愛有趣的文字,生活和遠方。
個人博客:https://blog.csdn.net/weixin_45791445
編程要求(實現三個線程間隔運行)
實現代碼
package step3;
public class MyThread implements Runnable {
private String name;
private Object prev;
private Object self;
private MyThread(String name, Object prev, Object self) {
this.name = name;
this.prev = prev;
this.self = self;
}
public void run() {
int count = 5;
while (count > 0) {
synchronized (prev) {
synchronized (self) {
System.out.print(name);
count--;
self.notify();
}
try {
prev.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.exit(0);
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
Object c = new Object();
MyThread pa = new MyThread("E", c, a);
MyThread pb = new MyThread("D", a, b);
MyThread pc = new MyThread("U", b, c);
new Thread(pa).start();
Thread.sleep(100);
new Thread(pb).start();
Thread.sleep(100);
new Thread(pc).start();
Thread.sleep(100);
}
}
類似題目(實現兩個線程間隔運行)
實現代碼
public class MyThread implements Runnable {
private String name;
private Object prev;
private Object self;
private MyThread(String name, Object prev, Object self) {
this.name = name;
this.prev = prev;
this.self = self;
}
public void run() {
int count = 5;
while (count > 0) {
synchronized (prev) {
synchronized (self) {
System.out.print(name);
count--;
self.notify();
}
try {
prev.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.exit(0);//退出jvm
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object b = new Object();
MyThread ta = new MyThread("A", b, a);
MyThread tb = new MyThread("B", a, b);
new Thread(ta).start();
Thread.sleep(100); //確保按順序A、B執行
new Thread(tb).start();
Thread.sleep(100);
}
}
運行結果
ABABABABAB
上面兩道分別實現了將三個字母間隔輸出和將兩個字母間隔輸出 。小白推薦大家可以去找找不同,這樣有助於理解,看看實現了間隔輸出的是那一部分,而實現了間隔輸出兩個或者三個的不同在哪裏?
下面是小白對於代碼的解釋。
對象鎖。同一時間只保證 一個線程訪問方法或變量。
在Java語言中,通過被關鍵字synchronized修飾的方法或synchronized語句塊實現對代碼的同步
包含在synchronized方法或語句塊中的代碼稱爲被同步的代碼(Synchronized Code)
當線程訪問被同步的代碼時,必須首先競爭代碼所屬的類的【對象上的鎖】,否則線程將等待(阻塞),直到鎖被釋放。
wait()就是說線程在獲取對象鎖後,主動釋放對象鎖,同時本線程休眠。直到有其它線程調用對象的notify()喚醒該線程,才能繼續獲取對象鎖,並繼續執行;
相應的notify()會喚醒其它等待該對象鎖的出於堵塞狀態的線程,並釋放該對象鎖操作。但有一點需要注意的是notify()調用後,並不是馬上就釋放對象鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖。然後JVM會在wait()對象鎖的線程中隨機選取一線程,賦予其對象鎖,喚醒線程,繼續執行。這樣就提供了在線程間隔同步、喚醒的操作。
Thread.sleep()與Object.wait()二者都可以暫停當前線程,釋放CPU控制權,主要的區別在於Object.wait()在釋放CPU同時,釋放了對象鎖的控制。
對第二道題進行講解
首先看一張圖,後面會用
解釋
-
首先
代碼段1:MyThread ta = new MyThread(“A”, b, a);
MyThread tb = new MyThread(“B”, a, b);
實例化了對象ta和對象tb,由代碼段3可知
此時在對象ta中name=“A” , prev=b , self=a;
對象tb中name=“B”,prev=a,self=b;
代碼段2:new Thread(ta).start();
將這個對象創建一個新的線程(後面用線程ta來代表),並調用start方法將線程ta就緒,由於此時沒有其它線程,此線程或得CPU執行權開始運行,調用對應的run()方法。
在run方法中
所先,synchronized保證了只有一個線程能夠進入運行(實現原理),所以此時線程ta持有prev(此時是實例對象鎖b)進入運行,然後
synchronized (self) {
System.out.print(name);
count--;
self.notify();
}
線程ta再次持有self(即實例對象鎖a)進入運行(此時線程ta持有實例對象鎖a,b),輸出name(即“A”),count-1,然後線程ta調用self.notify(),被轉化爲就緒狀態。 由於此時 被synchronized (self)包裹的代碼已經運行完畢,所以線程ta會釋放實例對象鎖a。 cpu再從同等優先級的線程中選擇某個線程去執行(還是有可能會選擇到此線程)。
然後線程ta調用了wait()方法,進入了堵塞狀態,暫時放棄對CPU的使用權,停止執行,就會釋放線程ta此時持有的對象鎖b。(爲什麼)然後調用notify()通知調用過wait方法的線程可以去參與獲得鎖的競爭了 。CPU則會再尋找一個新的線程去運行,而,
Thread.sleep(100); //確保按順序A、B執行
這一段代碼是爲了確保線程ta出於堵塞狀態。
此時程序繼續向下運行,
tb線程被由新建狀態轉化爲就緒狀態,由於ta線程出於堵塞狀態,處於就緒狀態的只有tb線程。tb線程開始運行。相同的,tb線程開始調用run方法,由於對象鎖b沒用被其它線程持有,tb拿到了對象鎖b,然後進入 synchronized 修飾的代碼塊中。同理,由於對象鎖a沒被佔用,所以拿到對象鎖a。進入代碼段,輸出“B”,然後線程tb調用self.notify(),被轉化爲就緒狀態。並且會喚醒等待對象鎖a的線程ta 由於此時 被synchronized (self)包裹的代碼已經運行完畢,所以線程tb會釋放實例對象鎖b。
然後,線程tb調用prev.wait();變爲堵塞狀態,釋放對象鎖a。
線程ta再次拿到了對象鎖b,已經對象鎖a。然後順利運行了下去,輸出“A”。當先後遇到self.notify();prev.wait();執行相同的操作,釋放其本身對象鎖a,喚醒出於堵塞狀態的線程tb,然後釋放實例對象鎖b。然後線程ta變爲堵塞狀態,等待線程tb運行到self.notify();時將它喚醒。
剩餘的過程就是上面的不斷循環,最終在count變爲0時,run()方法運行結束。線程死亡。
synchronized的實現原理
將synchronized作用於一個給定的實例對象(就是synchronized後面括號裏的,例如上面的代碼synchronized (prev)中的prev ),即當前實例對象就是鎖對象,每次當線程進入synchronized包裹的代碼塊時就會要求當前線程持有prev實例對象鎖,如果當前有其他線程正持有該對象鎖,那麼新到的線程就必須等待,這樣也就保證了每次只有一個線程執行i++;操作。
爲什麼線程ta會釋放它所持有的對象鎖
synchronized關鍵字修飾時,當此線程調用wait()方法後,就會釋放所持有的實例對象鎖。補充一下sleep()同樣是讓線程出於堵塞狀態,但是線程只會交出cpu的執行權,並不會釋放手中持有的鎖。
兄弟們,小白編寫不易。(這道題真的對於之前的小白而言,很燒腦。)希望各位兄弟們,點贊評論收藏加關注。小白在此謝謝各位老爺們。
對於白嫖的兄弟們,