Java多线程安全问题(原子性,内存可见性,指令重排序)

概述

多线程虽然是更轻量的(相比于多进程来说)来完成了并发编程。但是多个线程是访问同一份内存资源的。并且线程是一个“抢占式”执行的过程(这些线程谁先执行,谁后执行,完全取决于系统的调度器),由于这里的不确定性太多,就可能会导致多个线程在访问同一个资源的时候,出现bug~“线程安全问题”。

举个例子:在一个桌子上放着一盘鸡肉,张三和李四老铁,同时看上了一个鸡大腿,两个人都要去抢这个鸡大腿,这个时候,两人就可能会打起来。
就好比线程1和线程2同时争夺一个资源,就会发生线程不安全问题。

那么这里的“访问” 是啥意思呢?访问分为读和写。
1.如果 多个线程只是进行读操作~ ,那么就不会有线程安全问题~ 就好比张三和李四同时看上了鸡大腿,但是他们只是看看,不吃,这就无所谓。
2.如果 多个线程涉及到写操作~,就会有线程安全问题 ~ 张三和李四都想吃,就会产生矛盾,发生问题。

线程不安全代码演示:

两个线程同时修改一个变量;

public  class TestDemo {
   
    static  class Counter{
   
        public int count = 0;

        public void add(){
   
            count++;
        }
    }
    public static void main(String[] args) throws InterruptedException {
   
        Counter counter = new Counter();
        Thread t1 = new Thread(){
   
            @Override
            public void run() {
   
                for (int i = 0; i < 50000; i++) {
   
                    counter.add();
                }
            }
        };

        Thread t2 = new Thread(){
   
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JMM是Java Memory Model(Java内存模型)的缩写,它定义了Java程序中多线程并发访问共享变量时的行为规范。JMM的设计目的是为了保证多线程程序在不同的硬件和操作系统平台上的可移植,并提供一定的可见原子性保证。 排序是指编译器和处理器对指令的执行顺序进行优化的一种技术。由于指令排序,原本在代码中的先后顺序可能被打乱,但是这种排序不会影响单线程程序的执行结果。然而对于多线程程序来说,排序可能会导致线程安全问题。 可见是指当一个线程对共享变量进行了修改后,其他线程是否能够立即看到这个修改。在JMM中,由于为了能考虑,对于普通的共享变量,JVM会对读写操作进行排序,从而可能导致一个线程修改了共享变量后,其他线程无法立即看到这个修改的结果。为了保证可见,我们可以使用volatile关键字来修饰共享变量,强制线程对共享变量的读写操作都通过主内存进行,从而解决了可见问题原子性是指一个操作是不可中断的,要么全部执行成功,要么全部不执行。在多线程程序中,对于一些涉及到多步操作的操作,如果没有保证原子性,可能会导致线程安全问题。为了保证原子性,可以使用synchronized关键字或者Lock来进行同步,保证任意时刻只有一个线程可以执行这些操作,从而解决了原子性问题。 总之,JMM的排序、可见原子性是为了解决多线程程序中的线程安全问题而提出的。排序可能导致程序执行结果和预期不符,可见问题可能导致线程无法看到其他线程对共享变量的修改,原子性问题可能导致操作只完成了一部分而不是全部。通过合理地使用volatile关键字和同步机制,可以有效地解决这些问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值