java - 如果可以使用 synchronized(this),为什么还要使用 Reentrant

如果可以使用 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;
}

最佳答案

一个 ReentrantLock 是非结构化的,不像 synchronized 结构——也就是说,你不需要使用 block 结构来锁定,甚至可以跨方法持有锁。一个例子:

private ReentrantLock lock;

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

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

这样的流程不可能通过 synchronized 构造中的单个监视器来表示。


除此之外,ReentrantLock 支持lock polling和 interruptible lock waits that support time-out . ReentrantLock 也支持configurable fairness policy ,允许更灵活的线程调度。

The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order. Programs using fair locks accessed by many threads may display lower overall throughput (i.e., 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. It will succeed if the lock is available even if other threads are waiting.


ReentrantLock 可能也可以是more scalable ,在更高的争用下表现更好。你可以阅读更多关于这个 here .

然而,这一说法受到了质疑;请参阅以下评论:

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.


什么时候应该使用ReentrantLock?根据那篇 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. 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. 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. 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.


在不久的将来会变得更加相关的最后一个方面与 Java 15 and Project Loom 有关。 .在虚拟线程的(新)世界中,底层调度器使用 ReentrantLock 比使用 synchronized 工作得更好,至少在最初的 Java 15 版本,但以后可能会进行优化。

In the current Loom implementation, a virtual thread can be pinned in two situations: when there is a native frame on the stack — when Java code calls into native code (JNI) that then calls back into Java — and when inside a synchronized block or method. In those cases, blocking the virtual thread will block the physical thread that carries it. Once the native call completes or the monitor released (the synchronized block/method is exited) the thread is unpinned.

If you have a common I/O operation guarded by a synchronized, replace the monitor with a ReentrantLock to let your application benefit fully from Loom’s scalability boost even before we fix pinning by monitors (or, better yet, use the higher-performance StampedLock if you can).

关于java - 如果可以使用 synchronized(this),为什么还要使用 ReentrantLock?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11821801/

相关文章:

java - Java的隐藏特性

java - 使用 Mockito 模拟静态方法

java - 如何在 Java 中进行 URL 解码?

java - 是什么导致错误 "No enclosing instance of type Foo

java - Mockito:试图监视方法正在调用原始方法

java - 在Android应用程序中存储用户设置的最合适方法是什么

java - 如何在 Java 项目中查找未使用/死代码

java - 从字符串中删除所有出现的 char

java - 什么是 "continue"关键字,它在 Java 中是如何工作的?

java - 如何将输出流转换为输入流?