多线程安全和锁优化概述
Posted fesng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程安全和锁优化概述相关的知识,希望对你有一定的参考价值。
什么是线程安全?
通俗的说就是对象本身完成了同步优化,保证外部随意调用的不用在考虑同步,互斥,调配等问题
线程安全的5个等级
1.不可变。
基本类型是用final修饰,对于对象指的是行为不会改变内部状态。比如String类的操作都是返回一个新的String。还有Integer等类,内部变量都是final的。
2.绝对的线程安全
定义是:不管任何条件,调用者都不用做额外的同步措施。
实际是很难达到的。Vecter类,对于内部的add(),remove等方法,都做了一些syc操作。但是也不是绝对的线程安全,比如初始化一个vecter,然后创建两个线程,一个线程做remove,另一个做print。就会出错。
3.相对的线程安全
vecter就算是了,我们经常说的线程安全,就是这个。
4.线程兼容
线程不安全的。但是可以通过外部的措施,保证线程安全。
5.线程对立
无论是否是否采取措施,都无法在多线程中使用。
比如Thread的suspend和resume方法,一个是中断,一个初始化,如果多线程调用就会可能死锁,目前已经逐渐废弃。
线程安全的方法
1.互斥
互斥最常用的方法,同布是目的和结果
synchronized对用monitorenter monitorexit两条字节码指令是系统级别的支持,最常用的。
还有一种API级别的ReentranLock可重入锁。
ReentranLock还有一些syn没有的特性,比如等待中断(等一会,就不等了,不会出现持续阻塞的情况),公平锁(根据时间排队),绑定对象。
互斥实现同步缺点:
频繁的进行线程状态切换,涉及用户态到内核态的切换调度,需要对锁计数,判断是否有线程需要唤醒等
2.非阻塞同步
本质就是把一些非原子操作变为原子操作。
支持的有5种:
测试并设置(test-and-set)
获取并增加(fetch-and-add)
交互(swap)
比较并交换(compare-and-swap)
加载链接/条件存储(Load-link/Store-condition)
最常用的就是由这些这些指令封装的一些类。比如atomicInteger等Atomic系列的类,比如atomicInteger的IncreateAndGet()方法,实现增加,内部就调用了原子操作,compareA你的Set(旧值,新值)
3.无同步方案
线程安全不一定要同步,满足可重入性即可。
可重入代码:
任何时刻转移到其他代码,再回来程序不会出错。本质是无状态改变,任何输入的返回结果可预测。
锁优化
1.自旋锁和自适应自旋
本质就是遇到同步,先不阻塞,成本太高,就让处理器继续自旋状态,需要处理器的支持,缺点是自旋时间太长会影响处理器效率。
自适应自旋就是根据统计性能,自适应自旋的效果。
2.锁消除
本质是把不惜要的锁去掉。
比如字符串相加
String a1,a2,a3.
a1+ a2 +a3;
会变成StringBuilder.append(a1).append(a2).append(a3)
StringBuilder内部方法做了加锁互斥同步,有时候没必要,需要清除。
3.锁粗化
这个很好理解,如果锁太细粒度了,需要频繁的状态切换和调度。比如循环体里面加锁,干脆外部直接加一个大锁。
4.轻量级锁 和偏向锁
这两种锁本质都不是直接加锁。轻量级锁 本质是对于没有线程竞争的,标记为轻量级锁,遇到线程竞争再升级为经常的重量级锁,并在释放以后唤醒相应的线程。
偏向锁是什么也不做,偏向第一个使用对象的线程,当遇到其他线程来用的时候,再升级为重量锁。
与50位技术专家面对面 20年技术见证,附赠技术全景图以上是关于多线程安全和锁优化概述的主要内容,如果未能解决你的问题,请参考以下文章