多线程并发由于原子性引发的问题及其解决方案

本文讨论了在并发编程中,如何通过原子性操作(如AtomicInteger和synchronized)避免因共享变量导致的计数错误,重点介绍了AtomicInteger的自旋+CAS算法原理以及使用synchronized实现线程同步。
摘要由CSDN通过智能技术生成

原子性

所有操作作为一个不可分割的整体,操作要么同时成功,要么同时失败。

原子性问题引发的多线程问题:

现有如下问题我要让100个线程,每个线程送100朵花给小哈,但是最后发现不足10000朵花。

原因分析如下:

count++有如下操作:

1.线程将共享变量拷贝到线程栈副本

2.将副本的值++

3.将副本的值赋值给堆中的共享变量

如果在线程A在第二步还没到第三步,此时线程B进行第一步,则线程A、B执行count++以后,count在同一个值位置自增了两次,也就是少送了一朵花。

案例代码如下:

public class HuaThread implements Runnable {
    private int count = 0;
    @Override
    public void run() {
        for(int i = 0 ;i < 100; i ++){
            count++;
            System.out.println("给小哈送花第"+count+"朵");
        }
    }
}
​
public class Test {
    public static void main(String[] args) {
        HuaThread huaThread = new HuaThread();
​
        for(int i=0;i<100;i++){
            new Thread(huaThread).start();
        }
    }
}

解决方案1:AtomicInteger

原子整形类实现count++的整体一致性。

public class HuaThread implements Runnable {
    private AtomicInteger count = new AtomicInteger(0);
    @Override
    public void run() {
        for(int i = 0 ;i < 100; i ++){
            System.out.println("给小哈送花第"+count.incrementAndGet()+"朵");
        }
    }
}
​
public class Test {
    public static void main(String[] args) {
        HuaThread huaThread = new HuaThread();
​
        for(int i=0;i<100;i++){
            new Thread(huaThread).start();
        }
    }
}

解决方案2:synchronized

用synchronized同步代码块锁住访问共享资源的代码,每次只允许一个线程对共享数据操作。

public class HuaThread implements Runnable {
    private int count = 0;
    @Override
    public void run() {
        synchronized (this) {
            for(int i = 0 ;i < 100; i ++){
                count++;
                System.out.println("给小哈送花第"+count+"朵");
            }
        }
    }
}
​
public class Test {
    public static void main(String[] args) {
        HuaThread huaThread = new HuaThread();
​
        for(int i=0;i<100;i++){
            new Thread(huaThread).start();
        }
    }
}

AtomicInteger的原理

自旋+CAS算法

CAS算法中有三个操作数

1.内存值:也就是被修改的共享数据

2.旧值:从内存中读取的共享数据

3.要修改的值:旧值进行操作后的值

算法流程如下:

若旧值与内存中的值一致,则说明没有其他线程操作过共享数据,此时将内存中的值修改为要修改的值,修改成功;

若旧值与内存中的值不一致,说明其他线程操作过了内存中的值,此时修改失败,从内存中重新获取值,继续操作;(从内存中重新获取值的流程叫做自旋)

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值