【Java並發編程實戰】-----“J.U.C”:ReentrantLock之一簡介


注:由於要介紹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();
        }
    }
}

運行結果(部分):

2015072500001

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM