如果可以使用同步的(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. 可重入锁非常灵活,并且具有公平性策略,其中如果线程等待更长的时间,并且在当前执行的线程完成之后,我们可以确保等待时间更长的线程有机会访问共享资源,从而减少系统的吞吐量并使其更加耗时。

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