常用方式: int a = 12; //註意:通常情況下,這個會設置成一個類變數,比如說Segement中的段鎖與copyOnWriteArrayList中的全局鎖 final ReentrantLock lock = new ReentrantLock()...
常用方式:
int a = 12; //註意:通常情況下,這個會設置成一個類變數,比如說Segement中的段鎖與copyOnWriteArrayList中的全局鎖 final ReentrantLock lock = new ReentrantLock(); lock.lock();//獲取鎖 try { a++;//業務邏輯 } catch (Exception e) { }finally{ lock.unlock();//釋放鎖 }
1、非公平鎖獲取鎖的步驟lock()
基於CAS嘗試將state(鎖數量)從0設置為1
A、如果設置成功,設置當前線程為獨占鎖的線程;
B、如果設置失敗,還會再獲取一次鎖數量,
B1、如果鎖數量為0,再基於CAS嘗試將state(鎖數量)從0設置為1一次,如果設置成功,設置當前線程為獨占鎖的線程;
B2、如果鎖數量不為0或者上邊的嘗試又失敗了,查看當前線程是不是已經是獨占鎖的線程了,如果是,則將當前的鎖數量+1;
如果不是,則將該線程封裝在一個Node內,並加入到等待隊列中去。等待被其前一個線程節點喚醒。
2、公平鎖獲取鎖的步驟lock()
獲取一次鎖數量,
B1、如果鎖數量為0,如果當前線程是等待隊列中的頭節點,基於CAS嘗試將state(鎖數量)從0設置為1一次,如果設置成功,設置當前線程為獨占鎖的線程;
B2、如果鎖數量不為0或者當前線程不是等待隊列中的頭節點或者上邊的嘗試又失敗了,查看當前線程是不是已經是獨占鎖的線程了,如果是,則將當前的鎖數量+1;如果不是,則將該線程封裝在一個Node內,並加入到等待隊列中去。等待被其前一個線程節點喚醒。
3、解鎖的步驟
1)獲取當前的鎖數量,然後用這個鎖數量減去解鎖的數量(這裡為1),最後得出結果c
2)判斷當前線程是不是獨占鎖的線程,如果不是,拋出異常
3)如果c==0,說明鎖被成功釋放,將當前的獨占線程置為null,鎖數量置為0,返回true
4)如果c!=0,說明釋放鎖失敗,鎖數量置為c,返回false
5)如果鎖被釋放成功的話,喚醒距離頭節點最近的一個非取消的節點
4、ReentrantLock的四種獲取鎖方法對比
/** *獲取一個鎖 *三種情況: *1、如果當下這個鎖沒有被任何線程(包括當前線程)持有,則立即獲取鎖,鎖數量==1,之後再執行相應的業務邏輯 *2、如果當前線程正在持有這個鎖,那麼鎖數量+1,之後再執行相應的業務邏輯 *3、如果當下鎖被另一個線程所持有,則當前線程處於休眠狀態,直到獲得鎖之後,當前線程被喚醒,鎖數量==1,再執行相應的業務邏輯 * 簡言之,獲取鎖,如果鎖無法獲取,當前線程被阻塞,直到鎖可以獲取並獲取成功為止。 */ public void lock() { sync.lock();//調用NonfairSync(非公平鎖)或FairSync(公平鎖)的lock()方法 } /** * lockInterruptibly(): * 1、 在當前線程沒有被中斷的情況下獲取鎖。 * 2、如果獲取成功,方法結束。 * 3、如果鎖無法獲取,當前線程被阻塞,直到下麵情況發生: * 1)當前線程(被喚醒後)成功獲取鎖 * 2)當前線程被其他線程中斷 */ public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } /** * 四點註意: * 1、如果其他線程沒有持有這個鎖,立即返回true,設置鎖的數量為1 * 2、如果當前線程已經持有這個鎖了,那麼鎖數量+1,立即返回true * 3、如果其他線程占有這個鎖,該方法立即返回false * 4、要註意:這個鎖是非公平鎖(即無法用於公平鎖策略中) */ public boolean tryLock() { return sync.nonfairTryAcquire(1); } /** * 在指定時間內這個鎖某個時刻沒有被其他線程占有並且當前線程沒有被中斷,獲得這個鎖 * * 1)如果沒有其他線程占有這個鎖,則獲得這個鎖,立即返回true,鎖數量+1 * 2)如果當前線程已經持有這個鎖了,那麼鎖數量+1,立即返回true * 3)如果這個鎖被其他線程持有,當前線程阻塞,直到下麵三種情況發生: * A、當前線程(被喚醒後)成功的獲取鎖 * B、其他線程中斷了當前線程 * C、指定時間超時(如果時間<=0,根本就不會等待) * * 如果該鎖被用於公平鎖:如果有其他線程在等待,即使判斷出沒有其他線程占有這個鎖,當前線程也不會獲取這個鎖 */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }