如果可以使用同步的(this),爲什麼還要使用ReentrantLock?

本文翻譯自:Why use a ReentrantLock if one can use synchronized(this)?

I'm trying to understand what makes the lock in concurrency so important if one can use synchronized (this) . 我正在嘗試理解是什麼使併發鎖如此重要,如果一個人可以使用synchronized (this) In the dummy code below, I can do either: 在下面的虛擬代碼中,我可以執行以下任一操作:

  1. synchronized the entire method or synchronize the vulnerable area ( synchronized(this){...} ) 同步整個方法或同步易受攻擊的區域( synchronized(this){...}
  2. OR lock the vulnerable code area with a ReentrantLock. 或使用ReentrantLock鎖定易受攻擊的代碼區域。

Code: 碼:

    private final ReentrantLock lock = new ReentrantLock(); 
    private static List<Integer> ints;

    public Integer getResult(String name) { 
        .
        .
        .
        lock.lock();
        try {
            if (ints.size()==3) {
                ints=null;
                return -9;
            }   

            for (int x=0; x<ints.size(); x++) {
                System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
            }

        } finally {
            lock.unlock();
        } 
        return random;
}

#1樓

參考:https://stackoom.com/question/nbOD/如果可以使用同步的-this-爲什麼還要使用ReentrantLock


#2樓

ReentrantReadWriteLock is a specialized lock whereas synchronized(this) is a general purpose lock. ReentrantReadWriteLock是一個專用鎖,而synchronized(this)是一個通用鎖。 They are similar but not quite the same. 它們相似但不完全相同。

You are right in that you could use synchronized(this) instead of ReentrantReadWriteLock but the opposite is not always true. 沒錯,您可以使用synchronized(this)而不是ReentrantReadWriteLock但並非總是如此。

If you'd like to better understand what makes ReentrantReadWriteLock special look up some information about producer-consumer thread synchronization. 如果您想更好地理解ReentrantReadWriteLock特殊之處,請查找有關生產者-消費者線程同步的一些信息。

In general you can remember that whole-method synchronization and general purpose synchronization (using the synchronized keyword) can be used in most applications without thinking too much about the semantics of the synchronization but if you need to squeeze performance out of your code you may need to explore other more fine-grained, or special-purpose synchronization mechanisms. 通常,您可以記住,在大多數應用程序中都可以使用全方法同步和通用同步(使用synchronized關鍵字),而無需過多考慮同步的語義,但是如果您需要從代碼中壓縮性能,則可能需要探索其他更細粒度或專用的同步機制。

By the way, using synchronized(this) - and in general locking using a public class instance - can be problematic because it opens up your code to potential dead-locks because somebody else not knowingly might try to lock against your object somewhere else in the program. 順便說一句,使用synchronized(this) -以及通常使用公共類實例進行鎖定-可能會出現問題,因爲它會使您的代碼陷入潛在的死鎖,因爲其他人在不知情的情況下可能會嘗試鎖定您對象的其他位置。程序。


#3樓

A ReentrantLock is unstructured , unlike synchronized constructs -- ie you don't need to use a block structure for locking and can even hold a lock across methods. synchronized構造不同, ReentrantLock非結構化的 -即,您不需要使用塊結構進行鎖定,甚至可以跨方法持有鎖定。 An example: 一個例子:

private ReentrantLock lock;

public void foo() {
  ...
  lock.lock();
  ...
}

public void bar() {
  ...
  lock.unlock();
  ...
}

Such flow is impossible to represent via a single monitor in a synchronized construct. 這樣的流程不可能通過synchronized構造中的單個監視器來表示。


Aside from that, ReentrantLock supports lock polling and interruptible lock waits that support time-out . 除此之外, ReentrantLock支持鎖輪詢和支持ReentrantLock中斷鎖等待 ReentrantLock also has support for configurable fairness policy , allowing more flexible thread scheduling. ReentrantLock還支持可配置的公平性策略 ,從而允許更靈活的線程調度。

The constructor for this class accepts an optional fairness parameter. 此類的構造函數接受一個可選的fairness參數。 When set true , under contention, locks favor granting access to the longest-waiting thread. 設置爲true ,在爭用下,鎖傾向於授予對等待時間最長的線程的訪問。 Otherwise this lock does not guarantee any particular access order. 否則,此鎖不能保證任何特定的訪問順序。 Programs using fair locks accessed by many threads may display lower overall throughput (ie, are slower; often much slower) than those using the default setting, but have smaller variances in times to obtain locks and guarantee lack of starvation. 與使用默認設置的程序相比,使用許多線程訪問的公平鎖的程序可能會顯示較低的總體吞吐量(即,速度較慢;通常要慢得多),但獲得鎖的時間變化較小,並確保沒有飢餓。 Note however, that fairness of locks does not guarantee fairness of thread scheduling. 但是請注意,鎖的公平性不能保證線程調度的公平性。 Thus, one of many threads using a fair lock may obtain it multiple times in succession while other active threads are not progressing and not currently holding the lock. 因此,使用公平鎖的許多線程之一可能會連續多次獲得它,而其他活動線程沒有進行且當前未持有該鎖。 Also note that the untimed tryLock method does not honor the fairness setting. 還要注意,未定時的tryLock方法不支持公平設置。 It will succeed if the lock is available even if other threads are waiting. 如果鎖定可用,即使其他線程正在等待,它將成功。


ReentrantLock may also be more scalable , performing much better under higher contention. ReentrantLock 可能還具有更高的可伸縮性 ,在更高的競爭條件下性能更好。 You can read more about this here . 您可以在此處瞭解更多信息。

This claim has been contested, however; 但是,此主張遭到了質疑; see the following comment: 看到以下評論:

In the reentrant lock test, a new lock is created each time, thus there is no exclusive locking and the resulting data is invalid. 在可重入鎖測試中,每次都會創建一個新鎖,因此沒有互斥鎖,並且結果數據無效。 Also, the IBM link offers no source code for the underlying benchmark so its impossible to characterize whether the test was even conducted correctly. 另外,IBM鏈接不提供基礎基準測試的源代碼,因此無法描述測試是否正確進行。


When should you use ReentrantLock s? 什麼時候應該使用ReentrantLock According to that developerWorks article... 根據該developerWorks文章...

The answer is pretty simple -- use it when you actually need something it provides that synchronized doesn't, like timed lock waits, interruptible lock waits, non-block-structured locks, multiple condition variables, or lock polling. 答案很簡單-在您實際需要它提供synchronized不希望的東西時使用它,例如定時鎖等待,可中斷鎖等待,非塊結構鎖,多個條件變量或鎖輪詢。 ReentrantLock also has scalability benefits, and you should use it if you actually have a situation that exhibits high contention, but remember that the vast majority of synchronized blocks hardly ever exhibit any contention, let alone high contention. ReentrantLock還具有可伸縮性的好處,如果您實際遇到競爭激烈的情況,則應使用ReentrantLock ,但請記住,絕大多數synchronized塊幾乎從未表現出任何競爭,更不用說競爭激烈了。 I would advise developing with synchronization until synchronization has proven to be inadequate, rather than simply assuming "the performance will be better" if you use ReentrantLock . 我建議您進行同步開發,直到證明同步不充分爲止,而不是簡單地假設您使用ReentrantLock會認爲“性能會更好”。 Remember, these are advanced tools for advanced users. 請記住,這些是面向高級用戶的高級工具。 (And truly advanced users tend to prefer the simplest tools they can find until they're convinced the simple tools are inadequate.) As always, make it right first, and then worry about whether or not you have to make it faster. (並且,真正的高級用戶傾向於使用他們能找到的最簡單的工具,直到他們確信簡單的工具是不合適的。)與往常一樣,首先使其正確,然後再擔心是否必須使其更快。


#4樓

From oracle documentation page about ReentrantLock : 從有關ReentrantLock的 oracle文檔頁面:

A reentrant mutual exclusion Lock with the same basic behaviour and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities. 具有與使用同步方法和語句訪問的隱式監視器鎖相同的基本行爲和語義的可重入互斥鎖,但具有擴展功能。

  1. A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it. ReentrantLock由上一次成功鎖定但尚未解鎖的線程擁有。 A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. 當另一個線程不擁有該鎖時,調用該鎖的線程將成功返回該鎖。 The method will return immediately if the current thread already owns the lock. 如果當前線程已經擁有該鎖,則該方法將立即返回。

  2. The constructor for this class accepts an optional fairness parameter. 此類的構造函數接受一個可選的fairness參數。 When set true, under contention, locks favor granting access to the longest-waiting thread . 設置爲true時,在爭用下, 鎖傾向於授予對等待時間最長的線程的訪問 Otherwise this lock does not guarantee any particular access order. 否則,此鎖不能保證任何特定的訪問順序。

ReentrantLock key features as per this article 根據本文介紹的 ReentrantLock主要功能

  1. Ability to lock interruptibly. 能夠中斷鎖定。
  2. Ability to timeout while waiting for lock. 能夠在等待鎖定時超時。
  3. Power to create fair lock. 建立公平鎖定的權力。
  4. API to get list of waiting thread for lock. 用於獲取鎖等待線程列表的A​​PI。
  5. Flexibility to try for lock without blocking. 嘗試鎖定的靈活性而不會阻塞。

You can use ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock to further acquire control on granular locking on read and write operations. 您可以使用ReentrantReadWriteLock.ReadLock,ReentrantReadWriteLock.WriteLock進一步獲取對讀寫操作的粒度鎖定的控制。

Have a look at this article by Benjamen on usage of different type of ReentrantLocks 看看Benjamen的這篇文章 ,瞭解不同類型的ReentrantLocks的用法


#5樓

You can use reentrant locks with a fairness policy or timeout to avoid thread starvation. 您可以將可重入鎖與公平性策略或超時一起使用,以避免線程匱乏。 You can apply a thread fairness policy. 您可以應用線程公平性策略。 it will help avoid a thread waiting forever to get to your resources. 這將有助於避免線程永遠等待獲取您的資源。

private final ReentrantLock lock = new ReentrantLock(true);
//the param true turns on the fairness policy. 

The "fairness policy" picks the next runnable thread to execute. “公平策略”選擇下一個可運行的線程來執行。 It is based on priority, time since last run, blah blah 它基於優先級,自上次運行以來的時間等等

also, Synchronize can block indefinitely if it cant escape the block. 同樣,如果Synchronize無法逃避阻止,它可以無限期阻止。 Reentrantlock can have timeout set. Reentrantlock可以設置超時。


#6樓

Synchronized locks does not offer any mechanism of waiting queue in which after the execution of one thread any thread running in parallel can acquire the lock. 同步鎖不提供任何等待隊列的機制,在這種機制下,執行一個線程後,任何並行運行的線程都可以獲取該鎖。 Due to which the thread which is there in the system and running for a longer period of time never gets chance to access the shared resource thus leading to starvation. 由於存在於系統中並運行較長時間的線程永遠不會獲得訪問共享資源的機會,從而導致飢餓。

Reentrant locks are very much flexible and has a fairness policy in which if a thread is waiting for a longer time and after the completion of the currently executing thread we can make sure that the longer waiting thread gets the chance of accessing the shared resource hereby decreasing the throughput of the system and making it more time consuming. 可重入鎖非常靈活,並且具有公平性策略,其中如果線程等待更長的時間,並且在當前執行的線程完成之後,我們可以確保等待時間更長的線程有機會訪問共享資源,從而減少系統的吞吐量並使其更加耗時。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章