上一篇:多线程04--线程的有序性_fengxianaa的博客-CSDN博客
程序的原子性指整个程序中的所有 *** 作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节,有着“同生共死”的感觉。对线程而言,一个 *** 作一旦开始,就不会被其他线程所干扰。
java中必须借助于synchronized、Lock、锁等,来保证整块代码的原子性
/**
* volatile不能保证原子性
*/
class Demo2 implements Runnable {
volatile int a = 0;
@Override
public void run() {
for(int i =0;i<10000;i++){
a++;
}
}
}
public class T04_Volatile {
public static void main(String[] args) throws InterruptedException {
Demo2 d = new Demo2();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(d.a);
}
}
3. CAS
/**
* CAS: 全称 Compare And Set
* 过程:1. 先获取最新值a,
* 2. 进行CAS *** 作, *** 作时先判断值是否还是a,如果是就设置新值,如果不是,一直重复整个过程,称之为:自旋,
* 整个cas *** 作是CPU原语级,不可被打断,所以是原子性的
*
*
* 缺点:如果有大量的线程同时并发修改一个变量,那么可能会有很多线程会不停的自旋,这样性能就不好
*/
class Demo implements Runnable {
AtomicInteger a = new AtomicInteger(0);
@Override
public void run() {
for(int i =0;i<10000;i++){
a.incrementAndGet();
}
}
}
public class T01_Cas {
public static void main(String[] args) throws InterruptedException {
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(d.a);
}
}
流程图
LongAdder
/**
* LongAdder,使用分段CAS以及自动分段迁移,提高并发性,最后计算出各个段的和值
* 底层原理:
* 1. 首先有一个base值,刚开始多线程来不停的累加数值,都是对base进行累加的,这时候跟AtomicInteger没有区别
* 2. 如果线程数量过多,就会开始施行分段机制,内部会搞一个Cell数组,每个元素是一个数值分段。
* 这时,让大量的线程分别去对不同Cell内部的value值进行CAS累加 *** 作,这样就把CAS计算压力分散到了Cell数组的各个元素,提高效率
*
* 3. 内部实现了自动分段迁移的机制,也就是如果某个Cell的value执行CAS失败了,那么就会自动去找另外一个Cell分段内的value值进行CAS *** 作,
* 这样也解决了线程空旋转、自旋不停等待执行CAS *** 作的问题
*
* 4. 最后,如果你要从LongAdder中获取当前累加的总值,就会把base值和所有Cell分段数值加起来返回给你
*/
class Demo2 implements Runnable {
LongAdder a = new LongAdder();
@Override
public void run() {
for(int i =0;i<10000;i++){
a.increment();
}
}
}
public class T02_LongAdder{
public static void main(String[] args) throws InterruptedException {
Demo2 d = new Demo2();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();t2.start();
t1.join();t2.join();
System.out.println(d.a);
}
}
流程图
ABA问题:
int a =1;
1. 线程1 获取a的最新值后,准备CAS *** 作,但这时线程暂停
2. 线程2 修改a的值为2
3. 线程3 又修改a的值为1
4. 线程1 继续运行,修改a的值。
这种情况下,线程1 虽然可以修改成功,但是这个a已经不是最初的a了,中间经历了一些变化,可能含义不同了,如果修改成功,可能导致一些问题,这就是ABA问题。
解决:加时间戳或版本号
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)