同步与锁定

java.util.concurrentAPI 提供了一个名为 as 的类,它基本上会序列化控件以访问关键资源。它给出了诸如 和 之类的方法。Lockpark()unpark()

如果我们可以使用关键字和使用和方法,我们可以做类似的事情。synchronizedwait()notify() notifyAll()

我想知道其中哪一个在实践中更好,为什么?


答案 1

如果您只是锁定对象,我宁愿使用synchronized

例:

Lock.acquire();
doSomethingNifty(); // Throws a NPE!
Lock.release(); // Oh noes, we never release the lock!

你必须在任何地方明确地做。try{} finally{}

而使用同步,它非常清晰,不可能出错:

synchronized(myObject) {
    doSomethingNifty();
}

也就是说,对于更复杂的事情,你可能无法以如此干净的方式获取和释放,s可能更有用。老实说,我宁愿首先避免使用裸 s,而只是使用更复杂的并发控制,例如 a 或 a ,如果它们符合您的需要。LockLockCyclicBarrierLinkedBlockingQueue

我从来没有理由使用,或者可能有一些好的理由。wait()notify()


答案 2

我想知道其中哪一个在实践中更好,为什么?

我发现和(以及其他新类)只是工具箱的更多工具。我可以使用我的旧爪锤(关键字)完成我需要的大部分工作,但在某些情况下使用起来很尴尬。一旦我在工具箱中添加更多工具,其中一些尴尬的情况就变得简单得多:一个橡胶槌,一个球锤,一个撬棍和一些钉拳。但是,我的旧爪锤仍然看到它的份额。LockConditionconcurrentsynchronized

我不认为一个真的比另一个“更好”,而是每个都更适合不同的问题。简而言之,简单的模型和面向范围的性质有助于保护我免受代码中的错误的影响,但这些相同的优势有时在更复杂的场景中是障碍。正是这些更复杂的方案,并发包是为了帮助解决的。但是,使用此更高级别的构造需要在代码中进行更明确和仔细的管理。synchronized

===

我认为JavaDoc在描述和之间的区别方面做得很好(重点是我的):Locksynchronized

与使用同步方法和语句可以获得的锁定操作相比,锁定实现提供了更广泛的锁定操作。它们允许更灵活的结构,可能具有完全不同的属性,并且可能支持多个关联的 Condition 对象

...

使用同步方法或语句提供对与每个对象关联的隐式监视锁的访问,但强制所有锁的获取和释放都以块结构的方式进行:当获取多个锁时,它们必须以相反的顺序释放,并且所有锁必须在获取它们的同一词法范围内释放

虽然同步方法和语句的作用域机制使使用监视器锁进行编程变得更加容易,并且有助于避免许多涉及锁的常见编程错误,但在某些情况下,您需要以更灵活的方式使用锁。例如,用于遍历并发访问的数据结构的**某些算法*需要使用“手放手”或“链锁定”:您获取节点A的锁定,然后是节点B,然后释放A并获取C,然后释放B并获取D,依此类推。Lock 接口的实现允许以不同的范围获取和释放锁并允许以任何顺序获取和释放多个锁,从而允许使用此类技术。

随着灵活性的提高,责任也随之增加缺少块结构锁定会消除同步方法和语句中发生的锁定的自动释放。在大多数情况下,应使用以下成语:

...

锁定和解锁发生在不同的作用域中时,必须注意确保在保持锁定时执行的所有代码都受到 try-finally 或 try-catch 的保护,以确保在必要时释放锁定

Lock 实现通过使用同步方法和语句提供了额外的功能,方法是提供获取锁的非阻塞尝试 (tryLock())、尝试获取可中断的锁 (lockInterruptibly() 以及尝试获取可能超时的锁 (tryLock(long, TimeUnit))。

...


推荐