java并發(fā)之Lock接口的深入講解
在java的juc包為我們提供了各種各樣的鎖信息。如果細(xì)心來看其大部分都會實現(xiàn)一個名為LOCK的接口信息本文皆在幫你回顧Lock信息;
通過本文你將了解到如下內(nèi)容:
1.Lock和synchronized的對比
2.Lock中常見API的總結(jié)
synchronized面臨缺點鎖的出現(xiàn)主要是為了保證在并發(fā)訪問共享資源時不出現(xiàn)錯。 在java中如果不考慮性能損耗問題,那么對共享的資源信息加上synchrionzed關(guān)鍵字基本就可以解決大多數(shù)并發(fā)帶來的問題,但是也隨之帶來靈活性和效率上的問題:
效率方面:
1. 此種情況下鎖的釋放情況較少,很容易到導(dǎo)致一直獨占資源而導(dǎo)致性能的下降。
2. 當(dāng)我們試圖獲取鎖時不能直接指定具體條件
3. 不能中斷正在試圖獲得鎖的線程
靈活性:
1. 當(dāng)獲得鎖資源后,無法得知是否獲得鎖信息
2. 僅當(dāng)程序異常或順利執(zhí)行完時才會釋放鎖信息,缺乏主動釋放鎖的時機。
不適用的場景
場景1 :
當(dāng)我們使用synchronized時,假如某線程獲取到鎖之后由于要等待IO或者其他原因進(jìn)入阻塞狀態(tài),同時未釋放鎖信息,那么此時其他線程就只能一直等待。所以此時就需要synchronized有一種機制:避免等待的線程一直無期限地等待下去。場景2 :
在讀文件信息形式,不同線程的寫操作是相互沖突的。但是讀操作并不會導(dǎo)致沖突。如果我們不加考慮的為資源信息加上synchronized關(guān)鍵字,那么當(dāng)多線程同時操作時,只有一個線程可以獲取到資源,其他未獲得鎖信息的線程只能進(jìn)入等待狀態(tài),從而導(dǎo)致讀寫效率不高。
Lock接口Lock接口是對關(guān)鍵字synchronized的補充和擴展,它允許我們可以在線程安全的情況下更加靈活的操作共享資源信息。
常見用法:
1.lock(),unlock()
一般來說,使用Lock必須在try…catch…塊中進(jìn)行,并且將釋放鎖的操作放在finally塊中進(jìn)行。這是因為lock并不會像synchronized那樣在異常時釋放鎖,所以必須保證有手動釋放的過程,這樣才能保證其它線程有獲取鎖的機會。
// 加鎖lock.lock();try{ //處理任務(wù)}catch(Exception ex){}finally{ //釋放鎖 (鎖的釋放一般放入到finally塊中進(jìn)行,這樣保證了總會對鎖信息進(jìn)行釋放) lock.unlock(); }
2. tryLock() & tryLock(long time, TimeUnit unit)
tryLock()方法是有返回值的,它表示用來嘗試獲取鎖,如果獲取成功,則返回true;如果獲取失敗(即鎖已被其他線程獲取),則返回false,也就是說,這個方法無論如何都會立即返回即使其無法獲取到鎖也不會一致等待。
tryLock(long time, TimeUnit unit)方法和tryLock()方法是類似的,只不過區(qū)別在于這個方法在拿不到鎖時會等待一定的時間,在時間期限之內(nèi)如果還拿不到鎖,就返回false
如果一開始拿到鎖或者在等待期間內(nèi)拿到了鎖,則返回true。一般情況下,通過tryLock來獲取鎖時是這樣使用的:
Lock lock = ...;if(lock.tryLock()) { try{ //處理任務(wù) }catch(Exception ex){ }finally{ lock.unlock(); //釋放鎖 } }else { //如果不能獲取鎖,則直接做其他事情}
3. lockInterruptibly()
lockInterruptibly()方法比較特殊,當(dāng)通過這個方法去獲取鎖時,如果線程 正在等待獲取鎖,則這個線程能夠 響應(yīng)中斷,即中斷線程的等待狀態(tài)。
例如,當(dāng)兩個線程同時通過lock.lockInterruptibly()想獲取某個鎖時,假若此時線程A獲取到了鎖,而線程B只有在等待,那么對線程B調(diào)用threadB.interrupt()方法能夠中斷線程B的等待過程。
public void method() throws InterruptedException { lock.lockInterruptibly(); try { //..... } finally {lock.unlock(); } }
當(dāng)一個線程獲取了鎖之后,是不會被interrupt()方法中斷的。因為interrupt()方法只能中斷阻塞過程中的線程而不能中斷正在運行過程中的線程。而在 synchronized 中,當(dāng)一個線程處于等待某個鎖的狀態(tài),是無法被中斷的,只有一直等待下去,這也就是我們需要手動釋放鎖的原因。
給出如下的例子來進(jìn)行驗證:創(chuàng)建兩個線程來共同爭搶lock鎖信息
public class LockInterruptibly implements Runnable { private Lock lock = new ReentrantLock();public static void main(String[] args) { LockInterruptibly lockInterruptibly = new LockInterruptibly(); Thread thread0 = new Thread(lockInterruptibly); Thread thread1 = new Thread(lockInterruptibly); thread0.start(); try {Thread.sleep(2000); } catch (InterruptedException e) {e.printStackTrace(); } thread1.start(); thread1.interrupt();} // 任務(wù)執(zhí)行邏輯 @Override public void run() {System.out.println(Thread.currentThread().getName() + '嘗試獲取鎖');try { lock.lockInterruptibly(); try {System.out.println(Thread.currentThread().getName() + '獲取到了鎖');Thread.sleep(5000); } catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + '睡眠期間被中斷了'); } finally {lock.unlock();System.out.println(Thread.currentThread().getName() + '釋放了鎖'); }} catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + '獲得鎖期間被中斷了');} }}
執(zhí)行結(jié)果:
Thread-0嘗試獲取鎖Thread-0獲取到了鎖Thread-1嘗試獲取鎖Thread-1獲得鎖期間被中斷了Thread-0釋放了鎖
通過結(jié)果信息我們可以看出,lockInterruptibly()僅能中斷正在等待的線程信息,而無法中斷正在運行的線程。
對比 Lock和tryLock的區(qū)別lock和tryLock都可以獲取到鎖信息,但兩者之間還是存在些差異的。 具體如下:
1: lock拿不到鎖會一直等待。tryLock是去嘗試,拿不到就返回false,拿到返回true。
2: tryLock是可以被打斷的,被中斷的,lock是不可以。
// 實例代碼 public class LockDemo implements Runnable{ static Lock lock1 = new ReentrantLock(); @Override public void run() {// 分別演示 lock,trylock區(qū)別// lock1.lock();lock1.tryLock();System.out.println('線程 ' + Thread.currentThread().getName() + ' 獲取到鎖信息 '); } public static void main(String[] args) throws InterruptedException {LockDemo r1 = new LockDemo();LockDemo r2 = new LockDemo();r1.flag = true;r2.flag = false;Thread t1 = new Thread(r1);Thread t2 = new Thread(r2);t1.start();Thread.sleep(1000);// 中斷t2.start();t2.interrupt(); }}
結(jié)果信息:
當(dāng)執(zhí)行l(wèi)ock1.lock()時的輸出:可以看到lock方法并不能響應(yīng)中斷信息,如果不解鎖則會一致持有鎖信息!
對于tryLock而言其可以響應(yīng)中斷
本篇對Lock接口中常用到的Api進(jìn)行了分析和總結(jié),同時分析了Lock接口和synchronized關(guān)鍵之間的關(guān)系,希望對你能有所啟發(fā).
到此這篇關(guān)于java并發(fā)之Lock接口的文章就介紹到這了,更多相關(guān)java并發(fā)Lock接口內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
