在java中,解決同步問題,不少時候都會使用到synchronized和Lock,這二者都是在多線程併發時候常使用的鎖機制。java
synchronized是java中的一個關鍵字,也就是說是java內置的一個特性。當一個線程訪問一個被synchronized修飾的代碼塊,會自動獲取對應的一個鎖,並在執行該代碼塊時,其餘線程想訪問這個代碼塊,會一直處於等待狀態,自有等該線程釋放鎖後,其餘線程進行資源競爭,競爭獲取到鎖的線程才能訪問該代碼塊。多線程
線程釋放synchronized修飾的代碼塊鎖的方式有兩種:併發
採用synchronized關鍵字來實現同步,會致使若是存在多個線程想執行該代碼塊,而當前獲取到鎖的線程又沒有釋放鎖,可想而知,其餘線程只有一隻等待,這將嚴重印象執行效率。Lock鎖機制的出現就是爲了解決該現象。Lock是一個java接口,經過這個接口能夠實現同步,使用Lock時,用戶必須手動進行鎖的釋放,不然容易出現死鎖。ide
ReentranLock是Lock的惟一實現類。下面簡單介紹一下ReentranLock與synchronized的區別:測試
公平鎖:當線程A獲取訪問該對象,獲取到鎖後,此時內部存在一個計數器num+1,其餘線程想訪問該對象,就會進行排隊等待(等待隊列最前一個線程處於待喚醒狀態),直到線程A釋放鎖(num = 0),此時會喚醒處於待喚醒狀態的線程進行獲取鎖的操做,一直循環。若是線程A再次嘗試獲取該對象鎖是,會檢查該對象鎖釋放已經被佔用,若是被佔用,會作一次是否爲當前線程佔用鎖的判斷,若是是內部計數器num+1,而且不須要進入等待隊列,而是直接回去當前鎖。spa
非公平鎖:當線程A在釋放鎖後,等待對象的線程會進行資源競爭,競爭成功的線程將獲取該鎖,其餘線程繼續睡眠。操作系統
公平鎖是嚴格的以FIFO的方式進行鎖的競爭,可是非公平鎖是無序的鎖競爭,剛釋放鎖的線程很大程度上能比較快的獲取到鎖,隊列中的線程只能等待,因此非公平鎖可能會有「飢餓」的問題。可是重複的鎖獲取能減少線程之間的切換,而公平鎖則是嚴格的線程切換,這樣對操做系統的影響是比較大的,因此非公平鎖的吞吐量是大於公平鎖的,這也是爲何JDK將非公平鎖做爲默認的實現。線程
下面是接口Lock的方法:code
附上對接口Lock方法的測試,有什麼問題歡迎各位大佬留言評論。對象
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TestLock { // ReentrantLock爲Lock的惟一實現類 private Lock lock = new ReentrantLock(); /** * 測試使用lock 的 lock()方法 :若是鎖已經被其餘線程獲取,則等待 * @param thread */ public void testLock(Thread thread){ try { // 1.獲取鎖 lock.lock(); System.out.println("線程 " + thread.getName() + " 獲取了鎖!"); }catch (Exception e){ e.printStackTrace(); }finally { System.out.println("線程 " + thread.getName() + " 釋放了鎖!"); // 必須在 finally 中釋放鎖,防止死鎖 lock.unlock(); } } /** * 測試使用lock 的 lock()方法 :經過這個方法去獲取鎖時,若是線程正在等待獲取鎖,則這個線程可以響應中斷,即中斷線程的等待狀態。 * @param thread */ public void testLockInterruptibly(Thread thread){ try { // 1.獲取鎖 lock.lockInterruptibly(); System.out.println("線程 " + thread.getName() + " 獲取了鎖!"); Thread.sleep(3000); }catch (Exception e){ e.printStackTrace(); }finally { System.out.println("線程 " + thread.getName() + " 釋放了鎖!"); // 必須在 finally 中釋放鎖,防止死鎖 lock.unlock(); } } /** * 測試使用lock 的 tryLock()方法 :若是獲取成功,則返回true,若是獲取失敗(即鎖已被其餘線程獲取),則返回false * @param thread */ public void testTryLock(Thread thread){ if(lock.tryLock()){// 若是獲取到了鎖 try { System.out.println("線程 " + thread.getName() + " 獲取了鎖!"); Thread.sleep(3000); }catch (Exception e){ e.printStackTrace(); }finally { System.out.println("線程 " + thread.getName() + " 釋放了鎖!"); // 必須在 finally 中釋放鎖,防止死鎖 lock.unlock(); } }else { // 沒有獲取到鎖 System.out.println("線程 " + thread.getName() + " 沒有獲取到鎖!"); } } /** * 測試使用lock 的 tryLock(long time, TimeUnit unit)方法 :和tryLock()方法是相似的,只不過區別在於這個方法在拿不到鎖時會等待必定的時間, * 在時間期限以內若是還拿不到鎖,就返回false。若是若是一開始拿到鎖或者在等待期間內拿到了鎖,則返回true。 * @param thread */ public void testTryLock_time_unit(Thread thread){ try { if(lock.tryLock(1000, TimeUnit.MILLISECONDS)){// 若是獲取到了鎖 try { System.out.println("線程 " + thread.getName() + " 獲取了鎖!"); }catch (Exception e){ e.printStackTrace(); }finally { System.out.println("線程 " + thread.getName() + " 釋放了鎖!"); // 必須在 finally 中釋放鎖,防止死鎖 lock.unlock(); } }else { // 沒有獲取到鎖 System.out.println("線程 " + thread.getName() + " 沒有獲取到鎖!"); } } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args){ TestLock testLock = new TestLock(); Thread a = new Thread("A") { @Override public void run() { /*// 測試 lock() testLock.testLock(Thread.currentThread());*/ /*// 測試 lockInterruptibly() testLock.testLockInterruptibly(Thread.currentThread());*/ /*// 測試 tryLock() testLock.testTryLock(Thread.currentThread());*/ /*// 測試 tryLock(long time, TimeUnit unit) testLock.testTryLock_time_unit(Thread.currentThread());*/ testLock.testTryLock_time_unit(Thread.currentThread()); } }; Thread b = new Thread("B") { @Override public void run() { testLock.testTryLock(Thread.currentThread()); } }; a.start(); b.start(); } }