Synchronized同步塊的不足
在多線程環境下保證線程同步的方法大多是使用synchronized關鍵字,但是這個關鍵字在某些環境下是很死板的。其主要缺點如下:
(1)如果一個線程已經在一個synchronized塊中執行,另一個線程視圖進入這個同步塊,那麼它必須等待直到當前佔用這那個同步塊的線程執行完並退出。如果線程一直沒有進入同步塊,那麼那個等待的線程就一直處於阻塞狀態並且不能被interrupted!。
(2)當一個線程執行完同步塊代碼並退出後,任何一個等待進入的線程都可以獲得鎖去執行同步塊代碼,也就是說,有的線程可能一直沒有機會獲取這個機會去執行同步塊,也就是有可能會被餓死!。(3)Synchronized塊沒有任何方法去查詢那些爲使用特殊資源而等待的線程的狀態。
(4)Synchronized塊必須在相同的方法裏出現,也就是說一個同步塊不能在一個方法裏開始,在另一個方法裏結束。
Lock和Condition的基本應用
基於以上考慮,很多不適合Synchronized的場合可以使用Lock來解決!以下貼出基本的使用源碼:
public class LockMain {
//創建一把鎖
static Lock lock = new ReentrantLock();
// 創建第一個條件,B會用此條件等待,A會用此條件通知B開始任務
static Condition conditionA = lock.newCondition();
// 創建第二個個條件,C會用此條件等待,B會用此條件通知C開始任務
static Condition conditionB = lock.newCondition();
public static void main(String[] args) {
PersonA a = new PersonA();
PersonB b = new PersonB();
PersonC c = new PersonC();
// 爲了證實執行的順序是A、B、C,這裏特意先倒着開啓任務
new Thread(c).start();
new Thread(b).start();
new Thread(a).start();
}
/**
* 第一個人
*
* @author Administrator
*
*/
public static class PersonA implements Runnable {
public void run() {
lock.lock();
try {
// 模擬等待時間
Thread.sleep(3000);
// 辦理完後業務員會通知下一個人
System.out.println("A開始辦理...");
System.out.println("A辦理完畢,請下一位B到3號窗口");
conditionA.signal();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
// 用完之後記得釋放鎖,不然別人還是不能使用這個鎖
} finally {
// 一定要釋放鎖
lock.unlock();
}
}
}
/**
* 第二個人
*
* @author Administrator
*
*/
public static class PersonB implements Runnable {
public void run() {
lock.lock();
try {
// B只有等A辦理完了才能繼續辦
conditionA.await();
System.out.println("B開始辦理...");
System.out.println("B辦理完畢,請下一位C到3號窗口");
conditionB.signal();
// 辦理完後業務員會通知下一個人
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
/**
* 第三個人
*
* @author Administrator
*
*/
public static class PersonC implements Runnable {
public void run() {
lock.lock();
try {
// B只有等A辦理完了才能繼續辦
conditionB.await();
System.out.println("C開始辦理...");
System.out.println("C辦理完畢,準備下班吧");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
其用法就是辣麼簡單,我們再看下執行結果,是不是按照A、B、C的順序來的:
截圖已證實Lock和Condition的作用。下面我們開始一步步揭開Lock的神祕面紗。