concurrent API提供了一个名为Lock的类,它将序列化控件以访问关键资源。它给出了park()和unpark()等方法。

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

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


当前回答

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

我发现Lock和Condition(以及其他新的并发类)只是工具箱中的更多工具。我可以用我的旧羊角锤(synchronized关键字)做几乎所有我需要的事情,但在某些情况下使用它很尴尬。在我的工具箱里增加了一些工具后,一些尴尬的情况变得简单多了:一个橡胶槌,一个圆头锤,一根撬棍和一些钉子冲子。不过,我的旧羊角锤还能派上用场。

我不认为其中一个真的比另一个“更好”,而是每个都更适合不同的问题。简而言之,synchronized的简单模型和面向作用域的特性帮助我避免了代码中的错误,但在更复杂的场景中,这些相同的优点有时会成为障碍。并发包的创建就是为了帮助解决这些更复杂的场景。但是使用这种高级结构需要在代码中进行更明确和更仔细的管理。

===

我认为JavaDoc很好地描述了Lock和synchronized之间的区别(重点是我的):

Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements. They allow more flexible structuring, may have quite different properties, and may support multiple associated Condition objects. ... The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object, but forces all lock acquisition and release to occur in a block-structured way: when multiple locks are acquired they must be released in the opposite order, and all locks must be released in the same lexical scope in which they were acquired. While the scoping mechanism for synchronized methods and statements makes it much easier to program with monitor locks, and helps avoid many common programming errors involving locks, there are occasions where you need to work with locks in a more flexible way. For example, **some algorithms* for traversing concurrently accessed data structures require the use of "hand-over-hand" or "chain locking": you acquire the lock of node A, then node B, then release A and acquire C, then release B and acquire D and so on. Implementations of the Lock interface enable the use of such techniques by allowing a lock to be acquired and released in different scopes, and allowing multiple locks to be acquired and released in any order. With this increased flexibility comes additional responsibility. The absence of block-structured locking removes the automatic release of locks that occurs with synchronized methods and statements. In most cases, the following idiom should be used: ... When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary. Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)). ...

其他回答

为什么要使用synchronized或java.util.concurrent.Lock有4个主要因素。

注意:同步锁定就是我所说的内在锁定。

When Java 5 came out with ReentrantLocks, they proved to have quite a noticeble throughput difference then intrinsic locking. If youre looking for faster locking mechanism and are running 1.5 consider j.u.c.ReentrantLock. Java 6's intrinsic locking is now comparable. j.u.c.Lock has different mechanisms for locking. Lock interruptable - attempt to lock until the locking thread is interrupted; timed lock - attempt to lock for a certain amount of time and give up if you do not succeed; tryLock - attempt to lock, if some other thread is holding the lock give up. This all is included aside from the simple lock. Intrinsic locking only offers simple locking Style. If both 1 and 2 do not fall into categories of what you are concerned with most people, including myself, would find the intrinsic locking semenatics easier to read and less verbose then j.u.c.Lock locking. Multiple Conditions. An object you lock on can only be notified and waited for a single case. Lock's newCondition method allows for a single Lock to have mutliple reasons to await or signal. I have yet to actually need this functionality in practice, but is a nice feature for those who need it.

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

我发现Lock和Condition(以及其他新的并发类)只是工具箱中的更多工具。我可以用我的旧羊角锤(synchronized关键字)做几乎所有我需要的事情,但在某些情况下使用它很尴尬。在我的工具箱里增加了一些工具后,一些尴尬的情况变得简单多了:一个橡胶槌,一个圆头锤,一根撬棍和一些钉子冲子。不过,我的旧羊角锤还能派上用场。

我不认为其中一个真的比另一个“更好”,而是每个都更适合不同的问题。简而言之,synchronized的简单模型和面向作用域的特性帮助我避免了代码中的错误,但在更复杂的场景中,这些相同的优点有时会成为障碍。并发包的创建就是为了帮助解决这些更复杂的场景。但是使用这种高级结构需要在代码中进行更明确和更仔细的管理。

===

我认为JavaDoc很好地描述了Lock和synchronized之间的区别(重点是我的):

Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements. They allow more flexible structuring, may have quite different properties, and may support multiple associated Condition objects. ... The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object, but forces all lock acquisition and release to occur in a block-structured way: when multiple locks are acquired they must be released in the opposite order, and all locks must be released in the same lexical scope in which they were acquired. While the scoping mechanism for synchronized methods and statements makes it much easier to program with monitor locks, and helps avoid many common programming errors involving locks, there are occasions where you need to work with locks in a more flexible way. For example, **some algorithms* for traversing concurrently accessed data structures require the use of "hand-over-hand" or "chain locking": you acquire the lock of node A, then node B, then release A and acquire C, then release B and acquire D and so on. Implementations of the Lock interface enable the use of such techniques by allowing a lock to be acquired and released in different scopes, and allowing multiple locks to be acquired and released in any order. With this increased flexibility comes additional responsibility. The absence of block-structured locking removes the automatic release of locks that occurs with synchronized methods and statements. In most cases, the following idiom should be used: ... When locking and unlocking occur in different scopes, care must be taken to ensure that all code that is executed while the lock is held is protected by try-finally or try-catch to ensure that the lock is released when necessary. Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)). ...

Brian Goetz的《Java并发实践》一书,第13.3节: "...像默认的ReentrantLock一样,内在锁不提供确定性的公平性保证,但是 大多数锁定实现的统计公平性保证对于几乎所有情况都足够好……”

锁和同步的主要区别:

使用锁,您可以以任何顺序释放和获取锁。 使用synchronized,您只能按照获取锁的顺序释放锁。

锁和同步块都有相同的目的,但这取决于使用情况。考虑以下部分

void randomFunction(){
.
.
.
synchronize(this){
//do some functionality
}

.
.
.
synchronize(this)
{
// do some functionality
}


} // end of randomFunction

在上述情况下,如果一个线程进入同步块,另一个块也被锁定。如果在同一个对象上有多个这样的同步块,则所有的同步块都被锁定。在这种情况下,可以使用java.util.concurrent.Lock来防止不必要的块锁定