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

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

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


当前回答

你可以实现java.util.concurrent中的实用程序使用低级原语(如synchronized、volatile或wait / notify)所做的所有事情

然而,并发性是棘手的,大多数人至少在某些方面犯了错误,导致他们的代码要么不正确,要么效率低下(或两者兼而有之)。

并发API提供了更高级的方法,使用起来更容易(因此也更安全)。简而言之,你不应该再直接使用synchronized、volatile、wait、notify了。

Lock类本身在这个工具箱的底层,你甚至不需要直接使用它(你可以使用queue和Semaphore等等,大多数时候)。

其他回答

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

主要的区别是公平性,换句话说,请求是FIFO处理还是可以有驳船?方法级同步确保公平或FIFO分配锁。使用

synchronized(foo) {
}

or

lock.acquire(); .....lock.release();

不能保证公平。

如果您对锁有很多争用,那么您很容易遇到barging,即新请求获得锁而旧请求卡住。我曾经见过这样的情况:为了一个锁,200个线程在短时间内到达,而第二个到达的线程最后被处理。这对于某些应用程序是可行的,但对于其他应用程序则是致命的。

请参阅Brian Goetz的《Java并发实践》一书中的13.3节,以获得关于此主题的完整讨论。

我想在Bert F答案的基础上再补充一些东西。

锁支持用于更细粒度锁控制的各种方法,这些方法比隐式监控器(同步锁)更具表现力。

Lock提供对共享资源的独占访问:一次只有一个线程可以获得锁,并且对共享资源的所有访问都要求首先获得锁。但是,有些锁可能允许对共享资源的并发访问,例如ReadWriteLock的读锁。

从文档页面来看,锁定相对于同步的优势

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 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)). A Lock class can also provide behavior and semantics that is quite different from that of the implicit monitor lock, such as guaranteed ordering, non-reentrant usage, or deadlock detection

ReentrantLock:简单来说,根据我的理解,ReentrantLock允许一个对象从一个临界区重新进入到另一个临界区。由于您已经锁定进入一个临界区,您可以使用当前锁定进入同一对象的其他临界区。

ReentrantLock键的特性如本文所述

能够可中断地锁定。 能力超时,而等待锁定。 创造公平锁的权力。 API来获取等待锁的线程列表。 灵活地尝试锁定而不阻塞。

你可以使用ReentrantReadWriteLock。ReadLock ReentrantReadWriteLock。WriteLock以进一步获得对读写操作的粒度锁的控制。

除了这三个reentrantlock之外,java 8还提供了另外一个Lock

StampedLock:

Java 8附带了一种名为StampedLock的新锁,它也支持读写锁,就像上面的例子一样。与ReadWriteLock相反,StampedLock的锁定方法返回一个由长值表示的戳。

您可以使用这些戳记来释放锁或检查锁是否仍然有效。此外,戳锁支持另一种锁模式,称为乐观锁。

本文介绍了不同类型的ReentrantLock和StampedLock锁的用法。

锁和同步的主要区别:

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

你可以实现java.util.concurrent中的实用程序使用低级原语(如synchronized、volatile或wait / notify)所做的所有事情

然而,并发性是棘手的,大多数人至少在某些方面犯了错误,导致他们的代码要么不正确,要么效率低下(或两者兼而有之)。

并发API提供了更高级的方法,使用起来更容易(因此也更安全)。简而言之,你不应该再直接使用synchronized、volatile、wait、notify了。

Lock类本身在这个工具箱的底层,你甚至不需要直接使用它(你可以使用queue和Semaphore等等,大多数时候)。