多线程并发下,产生安全问题要满足以下三个条件:
为什么会有多线程下,线程安全的问题?
这里就涉及到Java虚拟机(简称JVM)的相关知识了。JVM启动后,本地内存分配给JVM一定的内存空间,称为“主内存”;而线程间又有各自独立的“工作内存”,工作内存中的数据来源于主内存数据的拷贝。正因为这个拷贝,工作内存的数据它不是原版数据,工作内存可能被其他线程所修改,这时候就有数据不一致的问题。
开发中,如何解决线程安全问题?
核心思想:
Java线程安全问题理解
volatile修饰的变量具有如下特性:
什么是可见性?
可见性:多个线程访问同一个共享变量时,其中一个线程对这个共享变量值的修改,其他线程能够立刻获得修改以后的值
什么是有序性?
有序性:编译器和处理器为了优化程序性能而对指令序列进行重排序,也就是你编写的代码顺序和最终执行的指令顺序是不一致的。
但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
volatile如何保证可见性?
总结为一句话:通过内存屏障和禁止指令重排保证可见性。
具体分析如下:
JMM内存模型下,数据操作通过如下8种方式:
read(读取):从主内存读取数据load(载入):将主内存的数据写入工作内存use(使用):从工作内存读取数据计算assign(赋值):将计算好的值重新赋值到工作内存中store(存储):将工作内存的值写入主内存write(写入):将store过去的变量值赋值给主内存中的变量lock(锁定):将主内存变量枷锁,标识未线程独占状态unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量volatile修饰的变量在写入操作时,在写入后,加入5、store(存储)内存屏障。(写入后,将工作内存中的数据写入主内存)
volatile修饰的变量在读取操作时,在读取前,加入2、load(载入)内存屏障。(读取前,从主内存中读取数据刷到工作内存)
如上一来,volatile读取的数据是主内存中数据,一定是最新的,因此能够保证可见性。
volatile如何保证可见性
synchronized可以用来修饰 代码块 或 方法。
修饰方法
同步方法的常量池有ACC_SYNCHRONIZED标识,线程访问方法时会判断是否有ACC_SYNCHRONIZED标识。
如果有,则先获取监视器锁,然后执行方法,最后释放监视器锁。
如果有,且获取监视器锁失败,则会阻塞,直到监视器锁被其他线程释放后,获取到监视器锁。
在发生异常的情况且没有处理异常,则在异常抛出前会释放监视器锁。
修饰代码块
修饰代码块时,底层会加入monitorenter和monitorexit指令。
每个对象都有一个锁次数的计数器,未被锁的计数器为0.
当线程进入代码块时,执行monitorenter指令,锁次数计数器 +1,当该线程再次获取锁时,则再次+1。
当执行monitorexit释放锁时,锁次数计数器-1。
直到锁次数计数器为0时,锁被释放,此时其他线程能够得到该代码块的锁。
1、synchronized是关键字,lock是接口。
2、synchronized是隐式加锁,lock是API层面的加锁。
3、synchronized可以作用在方法和代码块,lock只能作用在代码块。
4、synchronized是阻塞式加锁,lock支持非阻塞式加锁。
5、synchronized没有超时机制,lock中的tryLock支持超时机制。
6、synchronized不可中断,lock中的lockInterruptibly()中断获取的锁。
7、synchronized底层采用monitor;lock底层采用AQS。
8、synchronized是非公平锁;lock支持非公平锁与公平锁。
9、synchronized唤醒方式是notify/notifyAll;lock唤醒方式是condition。
CAS:Compare AND Swap,比较并交换。是一种通过乐观锁保证变量操作原子性的机制。
该方法包含3个操作数:内存位置、预期原值、新值,先通过 内存位置定位变量,比较 预期原值与当前 内存位置中的值是否一致;一致则会进行修改;不一致则不做如何操作。
优点:
资源竞争不大的情况下,系统开销小。
缺点:
1、ABA问题
2、竞争大的情况下,CPU开销大
主线程通过CAS在取出指定 内存位置的值后,比较 预期原值并修改操作之前,有一定的时间差;在这个时间差内,其他线程将A修改为B,又将B修改为A,此时主线程并不会发觉内存位置的值已被修改过,会继续进行 比较预期原值并修改操作。
尽管主线程的CAS操作完成,但这个过程是有风险的。
解决方案:
加上版本号解决ABA问题:只有版本号一致的情况下才能进行修改操作,每次修改操作都对 版本号执行+1操作。
适用场景为:冲突不频繁的业务下。
现有的数据库中,对于多数表会增加一个version字段,该字段能够有效避免数据修改的ABA问题。
上一篇:mac系统手册(帮助/说明)
下一篇:数据结构排序比较