从概念上讲,
Mutex
Reader's/Writer lock (Better form of Mutex)
Semaphore
Condition Variable
用作四种主要的同步机制,它们纯粹是基于锁的。不同的编程语言对这4种机制有不同的术语/术语。 POSIX pthread
包就是这种实现的一个例子。
前两个使用自旋锁实现(忙碌等待)。
最后两个使用睡眠锁实现。
基于锁定的同步在cpu周期方面很昂贵。
但是,我了解到java.util.concurrent
包不使用基于锁(睡眠/旋转)的机制来实现同步。
我的问题:
java并发包用于实现同步的机制是什么?因为自旋锁是cpu密集型的,并且由于频繁的上下文切换,睡眠锁比自旋锁更昂贵。
答案 0 :(得分:3)
这在很大程度上取决于您使用的java.util.concurrent包的哪些部分(在较小程度上取决于实现)。例如。从Java 1.7开始,LinkedBlockingQueue同时使用ReentrantLocks和Conditions,例如java.util.concurrent.atomic类或CopyOnWrite *类依赖于volatiles + native方法(插入适当的内存屏障)。
Locks,Semaphores等的实际原生实现也因架构和实现而异。
编辑:如果您真的关心性能,则应measure执行特定工作负载。在JVM团队中,有些人比我更聪明,比如A. Shipilev(他们的网站是关于这个主题的大量信息),他们这样做并且非常关心JVM的性能。
答案 1 :(得分:2)
通过查看source code for java.util.concurrent
可以最好地回答这个问题。准确的实现取决于您所指的类。
例如,许多实现都使用了volatile
数据和sun.misc.Unsafe
,这些数据延迟了比较和交换到本机操作。 Semaphore
(通过AbstractQueuedSynchronizer
)大量使用此功能。
您可以浏览那里的其他对象(使用该站点左侧的导航窗格)来查看其他同步对象及其实现方式。
答案 2 :(得分:0)
简短的回答是否定的。
与同步集合相比,并不使用锁实现并发集合。
我自己有与问题完全相同的问题,希望始终了解细节。是什么帮助我最终完全理解幕后发生的事情是在实践中阅读以下java并发章节:
5.1同步集合
5.2并发收藏
这个想法是基于做原子操作,基本上不需要锁定,因为它们是原子的。
答案 3 :(得分:0)
OP的问题和评论交换似乎包含了相当多的混乱。我会避免回答文字问题,而是试着概述一下。
为什么java.util.concurrent
成为今天的推荐做法?
因为它鼓励良好的应用程序编码模式。潜在的性能提升(可能会或可能不会实现)是一个奖励,但即使没有性能提升,仍然建议java.util.concurrent
,因为它可以帮助人们编写正确的代码。快速但有缺陷的代码没有任何价值。
java.util.concurrent
如何鼓励良好的编码模式?
在很多方面。我将列出一些。
(免责声明:我来自C#背景,并没有全面的Java并发包知识;虽然Java和C#对应物之间存在很多相似之处。)
并发数据收集简化了代码。
两大类并发数据收集类
有两种并发数据收集类。它们专为满足不同的应用需求而设计。要从“良好的编码模式”中受益,您必须知道在每种情况下使用哪种模式。
还有一种混合:阻止并发数据集合,允许人们进行快速(非阻塞)检查以查看操作是否成功。这种快速检查会受到“使用时间检查”竞争条件的影响,但如果使用得当,它可能对某些算法有用。
在java.util.concurrent
软件包可用之前,程序员经常需要编写自己的穷人代码。很多时候,这些糟糕的替代方案都有隐藏的错误。
除了数据收集?
Callable
,Future
和Executor
对于并发处理非常有用。可以说这些模式提供了与命令式编程范式截然不同的东西。
现在,应用程序可以:
,而不是指定许多任务的确切执行顺序Callable
允许将“工作单元”与要处理的数据打包在一起Future
为不同的工作单元提供了一种表达订单依赖关系的方法 - 哪个工作单位必须在另一个工作单位之前完成,等等。
Callable
实例没有表明任何顺序依赖关系,那么如果机器能够并行执行,它们可能会同时执行。Executor
指定有关如何执行这些工作单元的政策(约束)和策略。据报道原始java.util.concurrent
中遗漏了一件大事,就是当Callable
成功完成Future
提交给Executor
时,能够安排新ListenableFuture
}}。有些提案要求Task.WhenAny
。
(在C#中,类似的工作单元可组合性称为Task.WhenAll
和{{1}}。它们共同表达了许多众所周知的多线程执行模式,而无需明确使用自己的代码创建和销毁线程。)