synchronized
問題為三線程間的同步喚醒操作,主要的目的就是ThreadA->ThreadB->ThreadC→ThreadA……迴圈執行三個線程。為了控制線程執行的順序,那麼就必須要確定喚醒、等待的順序,所以每一個線程必須同時持有兩個對象鎖,才能繼續執行。一個對象鎖是prev,就是前一個線程所持有的對象鎖。還有一個就是自身對象鎖。
主要的思想就是,為了控制執行的順序,必須要先持有prev鎖,也就是前一個線程要釋放自身對象鎖,再去申請自身對象鎖,兩者兼備時列印字母,之後首先調用self.notifyAll()釋放自身對象鎖,喚醒下一個等待線程,再調用prev.wait()釋放prev對象鎖,終止當前線程,等待迴圈結束後再次被喚醒。程式啟動並執行主要過程就是A線程最先運行,持有C,A對象鎖,後釋放A,C鎖,喚醒B。線程B等待A鎖,再申請B鎖,後列印B,再釋放B,A鎖,喚醒C,線程C等待B鎖,再申請C鎖,後列印C,再釋放C,B鎖,喚醒A……
為了避免JVM啟動ThreadA、ThreadB、ThreadC三個線程順序的不確定性。需要讓A,B,C三個線程以確定的順序啟動,中間加一段sleep確保前一個線程已啟動。
public class ABC { public static class ThreadPrinter implements Runnable { private String name; private Object prev; private Object self; private ThreadPrinter(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; } @Override public void run() { int count = 10; while (count > 0) {//多線程並發,不能用if,必須用迴圈測試等待條件,避免虛假喚醒 synchronized (prev) { // 先擷取 prev 鎖 synchronized (self) {// 再擷取 self 鎖 System.out.print(name); count--; self.notifyAll();// 先釋放 self,喚醒其他線程競爭self鎖 } try { prev.wait(); // 再釋放 prev,休眠等待喚醒 /** * 注意的是notify()調用後,並不是馬上就釋放對象鎖,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖, * JVM會在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(); ThreadPrinter pa = new ThreadPrinter("A", c, a); ThreadPrinter pb = new ThreadPrinter("B", a, b); ThreadPrinter pc = new ThreadPrinter("C", b, c); new Thread(pa).start(); Thread.sleep(10); new Thread(pb).start(); Thread.sleep(10); new Thread(pc).start(); Thread.sleep(10); }} Lock
public class ABC_Lock { private static Lock lock = new ReentrantLock();//通過JDK5中的Lock鎖來保證線程的訪問的互斥 private static int state = 0; static class ThreadA extends Thread { @Override public void run() { for (int i = 0; i < 10; ) { try { lock.lock(); while (state % 3 == 0) {//多線程並發,不能用if,必須用迴圈測試等待條件,避免虛假喚醒 System.out.print("A"); state++; i++; } } finally { lock.unlock();// lock()和unlock()操作結合try/catch使用 } } } } static class ThreadB extends Thread { @Override public void run() { for (int i = 0; i < 10; ) { try { lock.lock(); while (state % 3 == 1) {//多線程並發,不能用if,必須用迴圈測試等待條件,避免虛假喚醒 System.out.print("B"); state++; i++; } } finally { lock.unlock();// lock()和unlock()操作結合try/catch使用 } } } } static class ThreadC extends Thread { @Override public void run() { for (int i = 0; i < 10; ) { try { lock.lock(); while (state % 3 == 2) {//多線程並發,不能用if,必須用迴圈測試等待條件,避免虛假喚醒 System.out.print("C"); state++; i++; } } finally { lock.unlock();// lock()和unlock()操作結合try/catch使用 } } } } public static void main(String[] args) { new ThreadA().start(); new ThreadB().start(); new ThreadC().start(); }} Condition
public class ABC_Condition { private static Lock lock = new ReentrantLock(); private static Condition A = lock.newCondition(); private static Condition B = lock.newCondition(); private static Condition C = lock.newCondition(); private static int count = 0; static class ThreadA extends Thread { @Override public void run() { try { lock.lock(); for (int i = 0; i < 10; i++) { while (count % 3 != 0) A.await(); // A釋放lock鎖 System.out.print("A"); count++; B.signal(); // A執行完喚醒B線程 } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } static class ThreadB extends Thread { @Override public void run() { try { lock.lock(); for (int i = 0; i < 10; i++) { while (count % 3 != 1) B.await();// B釋放lock鎖 System.out.print("B"); count++; C.signal();// B執行完喚醒C線程 } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } static class ThreadC extends Thread { @Override public void run() { try { lock.lock(); for (int i = 0; i < 10; i++) { while (count % 3 != 2) C.await();// C釋放lock鎖 System.out.println("C"); count++; A.signal();// C執行完喚醒A線程 } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public static void main(String[] args) throws InterruptedException { new ThreadA().start(); new ThreadB().start(); ThreadC threadC = new ThreadC(); threadC.start(); threadC.join();// main線程調用threadC.join(),會等threadC執行完成後,再執行main線程 System.out.println(count); }} Semaphore
public class ABC_Semaphore { // 以A開始的訊號量,初始訊號量數量為1 private static Semaphore A = new Semaphore(1); // B、C訊號量,A完成後開始,初始訊號數量為0 private static Semaphore B = new Semaphore(0); private static Semaphore C = new Semaphore(0); static class ThreadA extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { A.acquire();// A擷取訊號執行 System.out.print("A"); B.release();// B釋放訊號,B訊號量為1,可以執行 } } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadB extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { B.acquire(); System.out.print("B"); C.release(); } } catch (InterruptedException e) { e.printStackTrace(); } } } static class ThreadC extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { C.acquire(); System.out.println("C"); A.release(); } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { new ThreadA().start(); new ThreadB().start(); new ThreadC().start(); }}