您的位置:首页 > 编程语言 > Java开发

Java虚拟机高效并发-线程安全与锁优化

2018-02-11 20:48 288 查看

本文转载于http://blog.csdn.net/panweiwei1994/article/details/79146509

作者:潘威威

线程安全

[b]什么是线程安全[/b]当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方法进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象就是线程安全的。[b]线程安全级别[/b]不可变
绝对线程安全
相对线程安全
线程兼容
线程对立
不可变 
不可变的的数据一定是线程安全的。Java语言中,如果共享数据是基本数据类型,定义时使用final修饰就可以保证它是线程安全的。如果共享数据是一个对象,需要保证对象的行为不会对其状态产生影响。最简单的方法就是讲对象中带有状态的变量都声明为final。Java API中符合不可变条件的类型,有String,枚举,Number的部分子类,如Long、Double、BigInterger、BigDecimal,同为Number子类的AtomicInterger和AtomicLong则不是不可变的。绝对线程安全 
不管运行时环境如何,调用者都不需要额外的同步措施。这个要求是十分严格的。Java API中标明是线程安全的类都达不到这个要求,比如Vector。相对线程安全 
相对线程安全是指我们通常所说的线程安全。单线程环境下不需要做任何的额外措施。多线程环境下需要使用额外的同步手段来保证线程安全。Java API中标明是线程安全的类大都是这种类型,比如Vector,Hashtable。线程兼容 
线程兼容是指对象本身不是线程安全的,但可以通过同步手段来保证对象在并发环境中可以安全地使用。Java API中大部分的类都是这种类型,比如ArrayList,HashMap。线程对立 
指即使采用了同步手段,依然无法在并发环境中安全使用的代码。比如Thread.suspend()和resume()方法。[b]线程安全实现方法[/b]请参考Java并发编程札记-(一)基础-05线程安全问题-线程安全问题解决方法

锁优化

[b]锁优化内容[/b]高效并发是JDK1.5到JDK1.6的一个重要改进,HotSpot虚拟机开发团队在这个版本上实现了各种锁优化技术,比如自旋锁和适应性自旋
锁消除
锁粗化
轻量级锁
偏向锁
[b]自旋锁[/b]为什么需要自旋锁? 
互斥同步对性能最大的影响是阻塞,挂起线程和恢复线程的操作都需要转入内核态中完成,这给系统的并发性带来很大压力。同时很多应用共享数据的锁定状态只会持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得。自旋锁原理 
为了解决上述问题,先不挂起线程,让它等一会儿,说不定持有锁的线程很快就会释放锁了。为了让线程等待,我们只需要让线程执行一个自旋循环。这就是自旋锁。Java中的自旋锁
while(!object1 .compareAndSet(null, object2)){
。。。
}
上面的while循环在object1为null,且成功被设为object2前一直自旋。自旋锁的缺点? 
自旋等待本身虽然避免了线程切换的开销,但它要占用处理器时间。所以如果锁被占用的时间很短,自旋等待的效果就非常好,但如果时间很长,那么自旋的线程只会白白消耗处理器的资源。所以自旋等待的时间要有一定的限度,如果自旋超过了限定的次数仍然没有成功获得锁,那就应该使用传统的方式挂起线程了。自旋次数的默认值为10,可以通过参数-XX:PreBlockSpin来更改。适应性自旋 
JDK1.6中引入了自适应的自旋锁。自旋的时间不固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果一个锁对象,自旋等待刚刚成功获得锁,并且持有锁的线程正在运行,那么虚拟机认为这次自旋仍然可能成功,进而运行自旋等待更长的时间。如果对于某个锁,自旋很少成功,那在以后要获取这个锁,可能省略掉自旋过程,以免浪费处理器资源。有了自适应自旋,随着程序运行和性能监控信息的不断完善,虚拟机对程序锁的状况预测就会越来越准确,虚拟机也会越来越聪明。[b]锁消除[/b]锁消除是指虚拟机即时编译器在运行时对一些代码上要求同步,但被检测到不可能存在共享数据竞争,这是要对锁进行消除。锁消除的主要判定依据来源于逃逸分析的数据支持。程序员怎么会在明知道不存
a7a3
在数据竞争的情况下使用同步呢?答案是很多同步措施不是程序员自己加入的。[b]锁粗化[/b]原则上,同步块的作用范围要尽量小。这样做是为了使需要同步的操作数量尽可能变小。大部分情况下,上面的原则都是正确的,但如果一系列的连续操作都对同一个对象反复加锁和解锁,这样即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。锁粗化就是增大同步块的作用域。[b]轻量级锁[/b]在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。[b]偏量级锁[/b]消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。在无竞争的情况下,把整个同步都消除掉。这个锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: