为什么要使用的ReentrantLock如果可以使用同步(这)?(Why use a Reentra

2019-06-17 15:59发布

我想知道是什么使并发锁很重要,如果一个可以使用synchronized (this) 。 在下面的虚拟代码,我能做之一:

  1. 同步的整个方法或同步脆弱区( synchronized(this){...}
  2. 或锁定用的ReentrantLock漏洞代码的区域。

码:

    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;
}

Answer 1:

一个ReentrantLock的是非结构化的 ,不像synchronized结构-即你不需要使用块结构锁,甚至可以举行跨越方法的锁。 一个例子:

private ReentrantLock lock;

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

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

这种流动是不可能通过单个监视器的表示synchronized构建体。


除此之外, ReentrantLock支持锁定轮询和支持超时中断锁等待 。 ReentrantLock也有支持可配置的公平策略 ,允许更加灵活的线程调度。

这个类的构造函数接受一个可选的公平性参数。 如果设置true ,处于争,锁青睐授权访问等待时间最长的线程。 否则,此锁不保证任何特定访问顺序。 利用多线程访问公平锁定的程序可能会显示较低的整体吞吐量(即速度较慢,往往要慢得多),比使用默认设置的,但有个较小的差异,以获得锁和保证缺乏饥饿。 但是请注意,锁的公平性并不能保证线程调度的公平性。 因此,使用公平锁定多次可以获取它连续,而其他活动线程没有进行,当前未持有锁的线程之一。 还要注意的是无计时tryLock方法不遵守公平设置。 如果锁是即使其他线程正在等待可用它会成功。


ReentrantLock可能更具可扩展性 ,更高的竞争下进行好得多。 你可以阅读更多关于此这里 。

这种说法一直有争议然而,; 请参阅下面的注释:

在可重入锁定测试,一个新的锁被创建的每个时间,因而不存在排他锁定,并将所得数据是无效的。 此外,IBM的链接不提供源代码底层的基准所以它不可能表征该测试是否是正确的,即使进行。


当你应该使用ReentrantLock S' 根据该developerWorks文章...

答案很简单-用它当你真正需要的东西,它提供了synchronized不一样,定时锁定等待,可中断锁等候,无块结构锁,多个条件变量或者锁投票。 ReentrantLock还具有可扩展性的优势,您应该使用它,如果你确实有表现出高争的情况,但要记住的是,绝大多数的synchronized块几乎没有表现出任何的竞争,更别说高争。 我会建议使用同步发展,直到同步已被证明是不够的,而不是简单地假设“的表现会更好”,如果你使用ReentrantLock 。 请记住,这些都是高级用户的高级工具。 (和真正的高级用户更愿意他们可以找到,直到他们确信简单的工具不够用的简单工具。)像往常一样,使它正确,然后再担心你是否拥有,使其更快。



Answer 2:

ReentrantReadWriteLock is a specialized lock whereas synchronized(this) is a general purpose lock. 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.

If you'd like to better understand what makes ReentrantReadWriteLock special look up some information about producer-consumer thread synchronization.

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.

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.



Answer 3:

大约从Oracle文档页面的ReentrantLock :

使用synchronized方法和语句访问具有相同的基本行为和语义的隐式监视器锁定一个折返互斥锁,但功能更强大。

  1. 一个ReentrantLock的由线程拥有最后成功锁定,但尚未解锁的。 一个线程调用锁将返回,成功获取锁,当锁没有被另一个线程所拥有。 该方法将立即返回,如果当前线程已经拥有该锁。

  2. 这个类的构造函数接受一个可选的公平性参数。 当设置为true,处于争, 锁青睐授权访问等待时间最长的线程 。 否则,此锁不保证任何特定访问顺序。

ReentrantLock的主要特点为每本文章

  1. 能力可中断锁定。
  2. 能够在等待锁超时。
  3. 电力创造公平锁。
  4. API,让您的等待线程锁列表。
  5. 灵活地尝试了锁不阻塞。

您可以使用ReentrantReadWriteLock.ReadLock,ReentrantReadWriteLock.WriteLock还获取关于细粒度控制锁定读取和写入操作。

看看这个文章由Benjamen不同类型ReentrantLocks的用法



Answer 4:

您可以使用重入锁与公平策略或超时,避免线程匮乏。 你可以申请一个线程公平策略。 这将有助于避免一个线程等待永远让你的资源。

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

在“公平策略”挑选下一个可运行的线程来执行。 从去年来看,等等等等它是基于优先级,时间

同时,可以同步无限期阻塞,如果它不能逃脱块。 ReentrantLock的可以有超时设置。



Answer 5:

同步锁不提供等待队列中的任何机制,其中一个线程的执行之后并行运行的任何线程可以获取锁。 由于这是有系统和运行了较长一段时间的线程从来没有得到机会访问共享资源从而导致饥荒。

折返锁是非常灵活的,有一个公平的政策,其中,如果一个线程等待更长的时间,当前执行的线程完成后,我们可以确保较长的等待线程获取访问共享资源特此降低的机会吞吐量的系统,使其更费时的。



Answer 6:

让我们假设这个代码是在一个线程中运行:

private static ReentrantLock lock = new ReentrantLock();

void accessResource() {
    lock.lock();
    if( checkSomeCondition() ) {
        accessResource();
    }
    lock.unlock();
}

因为线程拥有锁它将允许多次调用锁定(),所以它重新进入锁。 这可以用引用计数来实现,因此不会有再次获取锁。



文章来源: Why use a ReentrantLock if one can use synchronized(this)?