注:由于要介紹ReentrantLock的東西太多了,免得各位客官看累,所以分三篇博客來闡述。本篇博客介紹ReentrantLock基本內容,后兩篇博客從源碼級別分別闡述ReentrantLock的lock、unlock實現機制。
ReentrantLock,可重入的互斥鎖,是一種遞歸無阻塞的同步機制。它可以等同于synchronized的使用,但是ReentrantLock提供了比synchronized更強大、靈活的鎖機制,可以減少死鎖發生的概率。
對于ReentrantLock,官方有詳細的說明:一個可重入的互斥鎖定 Lock,它具有與使用 synchronized 方法和語句所訪問的隱式監視器鎖定相同的一些基本行為和語義,但功能更強大。ReentrantLock 將由最近成功獲得鎖定,并且還沒有釋放該鎖定的線程所擁有。當鎖定沒有被另一個線程所擁有時,調用 lock 的線程將成功獲取該鎖定并返回。如果當前線程已經擁有該鎖定,此方法將立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法來檢查此情況是否發生。
ReentrantLock提供公平鎖機制,構造方法接收一個可選的公平參數。當設置為true時,它是公平鎖,這些所將訪問權授予等待時間最長的線程。否則該鎖將無法保證線程獲取鎖的訪問順序。但是公平鎖與非公平鎖相比,公平鎖的程序在許多線程訪問時表現為很低的總體吞吐量。
/** * 默認構造方法,非公平鎖 */ public ReentrantLock() { sync = new NonfairSync(); } /** * true公平鎖,false非公平鎖 * @param fair */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }以下是一個簡單的使用實例(【java7并發編程實戰手冊】):
public class PRintQueue { private final Lock queueLock = new ReentrantLock(); public void printJob(Object document){ try { queueLock.lock(); System.out.println(Thread.currentThread().getName() + ": Going to print a document"); Long duration = (long) (Math.random() * 10000); System.out.println(Thread.currentThread().getName() + ":PrintQueue: Printing a Job during " + (duration / 1000) + " seconds"); Thread.sleep(duration); System.out.printf(Thread.currentThread().getName() + ": The document has been printed/n"); } catch (InterruptedException e) { e.printStackTrace(); }finally{ queueLock.unlock(); } }}public class Job implements Runnable{ private PrintQueue printQueue; public Job(PrintQueue printQueue){ this.printQueue = printQueue; } @Override public void run() { printQueue.printJob(new Object()); }}public class Test { public static void main(String[] args) { PrintQueue printQueue = new PrintQueue(); Thread thread[]=new Thread[10]; for (int i = 0; i < 10; i++) { thread[i] = new Thread(new Job(printQueue), "Thread " + i); } for(int i = 0 ; i < 10 ; i++){ thread[i].start(); } }}
運行結果(部分):

ReentrantLock與synchronized的區別
前面提到ReentrantLock提供了比synchronized更加靈活和強大的鎖機制,那么它的靈活和強大之處在哪里呢?他們之間又有什么相異之處呢?
首先他們肯定具有相同的功能和內存語義。
1、與synchronized相比,ReentrantLock提供了更多,更加全面的功能,具備更強的擴展性。例如:時間鎖等候,可中斷鎖等候,鎖投票。
2、ReentrantLock還提供了條件Condition,對線程的等待、喚醒操作更加詳細和靈活,所以在多個條件變量和高度競爭鎖的地方,ReentrantLock更加適合(以后會闡述Condition)。
3、ReentrantLock提供了可輪詢的鎖請求。它會嘗試著去獲取鎖,如果成功則繼續,否則可以等到下次運行時處理,而synchronized則一旦進入鎖請求要么成功要么阻塞,所以相比synchronized而言,ReentrantLock會不容易產生死鎖些。
4、ReentrantLock支持更加靈活的同步代碼塊,但是使用synchronized時,只能在同一個synchronized塊結構中獲取和釋放。注:ReentrantLock的鎖釋放一定要在finally中處理,否則可能會產生嚴重的后果。
5、ReentrantLock支持中斷處理,且性能較synchronized會好些。
敬請關注下篇:【Java并發編程實戰】-----“J.U.C”:ReentrantLock之二lock()分析
參考文獻:
1、可重入的互斥鎖—ReentrantLock
2、再談重入鎖—ReentrantLock
3、ReentrantLock與synchronized
新聞熱點
疑難解答