线程安全问题

1. 为什么会出现线程安全问题?

原因 : 线程在系统中的调度是无序的/随机的(抢占式执行)

线程不安全的原因

1.1 抢占式执行

1.2 多个线程修改同一个变量

1.3 修改操作不是原子的

举个🌰

static class Counter{
    private int count = 0;
    public void add(){
          count++;
    }

    public int getCount() {
        return count;
    }
}

    public static void main(String[] args) throws InterruptedException{
        Counter counter = new Counter();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                counter.add();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(counter.getCount());
    }

两次运行结果都不一致    

       上述代码对变量 count 通过 线程 t1 和 线程 t2 进行 ++ 一万次 ,我们想要的结果是 20000,随着运行,结果却并不是.这里就是 系统 抢占式执行 造成的结果

我们来解析 ++ 这个 操作

这个时候我们要进行加锁操作

 

这里就是谁调用 add 谁进行加锁

还有一个线程不安全问题

内存可见性,造成线程不安全

举个🌰

private static int flag = 0;

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (flag == 0){

            }
            System.out.println("循环结束");
        });

        Thread t2 = new Thread(() -> {
            Scanner scan = new Scanner(System.in) ;
            System.out.println("请输入一个整数:");
            flag = scan.nextInt();
        });
        t1.start();
        t2.start();
    }

上述代码,我们创建两个线程, t1 中 变量 flag 为零 陷入死循环, t2 中,我们从键盘上输入一个整数,改变 flag 跳出循环,打印 循环结束,预期结果却并不是,而是 t1 还在跑,陷入死循环,这里就是内存可见性问题,导致线程不安全

while()  循环,会执行 load(从内存中读取数据到cpu中) 和 cmp(比较寄存器里的值是否为0) 操作

编译器发现 多次 load  的值都相同,就进行优化,使用上次的值,就会导致程序出现bug

解决方法 使用 volatile 关键字 

被 volatile 修饰的变量,就会阻止编译器进行优化,每次都会从内存中重新读取数据

 

 

这样就解决了,内存可见性导致的线程安全问题了

最后,volatile 关键字 还可以禁止指令重排序

画个图,给大家演示

 

 最后,祝大家身体健康,天天开心哦~ 🌹

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值