多线程—线程安全问题

首先看一段简单的代码:

/**
* 两个线程同时操作一个共享变量,可能会出现线程安全问题
*/
@Slf4j
public class Thread1 {
    private static int current;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
           for (int i = 0; i < 100 ; i++){
               current++;
           }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 100 ; i++){
                current--;
            }
        });
        t1.start();
        t2.start();
        log.debug("current的值:"+current);    
    }
}

声明一下,这段代大家测试的时候不一定会出现线程安全问题,我测试很多次,只出现过一次错误,我理解的原因可能是线程电脑性能比较好,但是不出现不代表不存在。接下来我们就一起分析分析这段简单的代码。

分析:

1、首先大家应该理解current++和current--不是原子性操作,(current为静态变量),JVM会产生如下字节码指令:

getstatic     current  //获取静态变量current的值   取值-->主线程
currentconst_1         //准备常量 1                取值-->子线程
currentadd             //自增                     计算-->子线程
putstatic     current  //将修改后的值存入静态变量current   存值——>主线程

2、因此,产生线程安全性问题的地方就是JVM在执行字节码指令的时候,分为四步操作,可能A线程读取了静态变量current的值,而计算之后还为来得及提交到主线程,A线程的时间片就已经用完了,而此时B线程去读取主线程的current值就不是A线程计算后的结果,还是原始的值,这样就会导致两个线程计算时取的值是一样的,而正确的应该是A线程取B线程计算完写到主线程的值,或者B线程取A线程计算完存到主线程的值,这样才会抵消。

3、解决:synchronized对象锁

@Slf4j
public class Thread1 {
    private static int current;
    private static Object object = new Object();
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(() -> {
           for (int i = 0; i < 100 ; i++){
               synchronized(object){  
                   current++;
               } 
           }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 100 ; i++){
                 synchronized(object){
                   current--;
               } 
            }
        });
        t1.start();
        t2.start();
        System.out.println(current);
    }
}

完事儿~

猜你喜欢

转载自blog.csdn.net/qq_42251944/article/details/120860237