Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么非阻塞并发优于阻塞并发_Java_Multithreading_Concurrency_Locking_Spinlock - Fatal编程技术网

Java 为什么非阻塞并发优于阻塞并发

Java 为什么非阻塞并发优于阻塞并发,java,multithreading,concurrency,locking,spinlock,Java,Multithreading,Concurrency,Locking,Spinlock,我只是想知道为什么非阻塞并发比阻塞并发好。在阻塞并发时,线程必须等待其他线程完成其执行。所以在这种情况下,线程不会占用CPU 但是如果我谈论非阻塞并发,线程不会等待获得锁,如果某些线程包含锁,它们会立即返回 例如,在ConcurrentHashMap类中,在put()方法中,循环中有tryLock()。由于tryLock()是非阻塞的,其他线程将处于活动状态,并持续尝试检查锁是否已被释放。我假设在这种情况下,不需要使用CPU 因此,在其他线程完成其执行之前挂起该线程,并在工作完成时唤醒该线程,这

我只是想知道为什么非阻塞并发比阻塞并发好。在阻塞并发时,线程必须等待其他线程完成其执行。所以在这种情况下,线程不会占用CPU

但是如果我谈论非阻塞并发,线程不会等待获得锁,如果某些线程包含锁,它们会立即返回

例如,在
ConcurrentHashMap
类中,在
put()
方法中,循环中有
tryLock()
。由于
tryLock()
是非阻塞的,其他线程将处于活动状态,并持续尝试检查锁是否已被释放。我假设在这种情况下,不需要使用CPU


因此,在其他线程完成其执行之前挂起该线程,并在工作完成时唤醒该线程,这样做不好吗?

阻塞或非阻塞并发性是否更好,取决于您希望等待多长时间才能获取您正在等待的资源

使用阻塞等待(即,用C的说法,使用互斥锁),操作系统内核将等待的线程置于睡眠状态。在所需资源可用之前,CPU调度程序不会为其分配任何时间。这里的优点是,正如您所说,这个线程在睡眠时不会消耗任何CPU资源

但也有一个缺点:将线程置于睡眠状态、确定何时唤醒线程以及再次唤醒线程的过程既复杂又昂贵,并且可能会抵消线程在等待时不消耗CPU所带来的节省。此外(可能正因为如此),一旦资源可用,操作系统可能会选择不立即唤醒线程,因此锁的等待时间可能比需要的时间更长

非阻塞等待(也称为自旋锁)在等待时确实会消耗CPU资源,但可以节省使线程进入睡眠、确定何时唤醒线程以及唤醒线程的费用。一旦锁被释放,它也可能能够更快地响应,因为在何时可以继续执行方面,操作系统的突发奇想就更少了


因此,作为一条非常普遍的规则,如果希望只等待很短的时间(例如,另一个线程在
ConcurrentHashMap
中完成一个条目可能需要的几个CPU周期),则应该选择自旋锁。对于较长的等待(例如在同步I/O或等待单个复杂计算的线程数),互斥(阻塞等待)可能是更好的。

< P>如果考虑CONCURNESHASMAP作为一个例子,考虑由于多线程执行更新操作(如PUT)的开销,以及等待锁释放的块。(正如您提到的,其他线程将处于活动状态,并不断尝试检查锁是否已释放),但情况并非总是如此

与哈希表相比,ConcurrentHashMap中的并发控制被拆分,所以多个线程可以获得锁(在表的段上)

最初,ConcurrentHashMap类支持32的硬连线预设并发级别。这允许最多32个put和/或remove操作同时进行(当超过32个线程同时尝试更新时,除同步之外的因素往往是瓶颈)

此外,使用get(key)和containsKey(key)成功地进行检索(当密钥存在时)通常不会锁定

因此,例如,一个线程可能正在添加一个元素,使用这种锁定策略无法完成的操作是添加一个元素(ConcurrentReaderHashMap提供了这样的工具)


此外,size()和isEmpty()方法需要在32个控制段之间进行累加,因此可能会稍微慢一些。

这取决于您是否需要(例如)您的整个程序将被阻止,因为有一件事尚未完成。ConcurrentHashMap不会锁定整个集合,因此2个以上的线程可以使用这种类型的集合,与同步hashmap相比,它提高了实例的性能短语“非阻塞等待”毫无意义。“等待”和“阻塞”两者的含义相同。等待旋转锁的线程被“阻塞”,因为它在其他线程释放该锁之前无法取得任何进展。不能将使用旋转锁的算法称为“非阻塞”因为如果挂起或终止已获取锁的线程,这将阻止其他需要获取锁的线程取得任何进展。@jameslarge我同意,我对使用这些术语感到紧张。但是,我决定继续使用OP使用的术语,因为我相信从这个问题上可以清楚地看出它们是什么我没有时间理解最初的问题。我不知道OP询问的ConcurrentHashMap.java源代码是什么。OpenJDK版本似乎没有使用tryLock().Spin locks,正如您所说,如果没有线程持有锁的时间超过很短的时间,那么它在多CPU系统上是有效的;但是如果仍然存在任何单CPU平台,那么您肯定不想在其上使用Spin lock。我通常相信,
ReentrantLock
的平台实现会起到一定作用对大多数使用模式来说,这是相当有效的。只有在实际性能测量证明我可以做得更好的情况下,我才会实现某种自定义锁定。@user31601那么我应该假设,我的问题一定是自旋锁比同步锁的优势,而不是为什么非阻塞并发比阻塞并发更好?是吗原因如上所述,很明显自旋锁使用的是非阻塞数据结构(tryLock()),但因为它用于紧密循环,所以它的行为就像阻塞算法一样。我们只想在多核上短时间阻塞