Back to Posts

i++线程安全问题

Posted in MultiThread

自加操作多线程读取时的问题

在《JAVA并发编程实战》中,解释了i++在多线程情况下的坑
我这里稍微模拟了一下:

package com.git.poan.multithreadpractice;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class UnsafeSequence {

    private int val;

    public int getNextVal() {
        return ++val;// 原书使用的是val++;感觉这样效果不直观 ,我用++val
    }

    public static void main(String[] args) {


        int threadNum = 2;

        ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
        UnsafeSequence unsafeSequence = new UnsafeSequence();
        for (int i = 0; i < threadNum; i++) {

            final int j = i;

            executorService.execute(() -> {

                Thread.currentThread().setName("thread-" + j);
                int nextVal = unsafeSequence.getNextVal();
                System.out.println(Thread.currentThread().getName() + "'s val:" + nextVal);
            });
        }


    }
}

从执行结果上看:

thread-0's val:1
thread-1's val:1

有一定的几率出现上述结果;

出现以上的结果,是因为getNextVal方法中,自己操作本省不是原子性的,实际上分成了三个指令:

  1. 加载常量1
  2. 执行val+1
  3. 将2的结果加载到val

实际情况中,如果有多个线程,这里举例用1号和2号线程,1号线程执行到2步骤,2号线程开始执行,那么2号读到的val还是0;
所以会出现两个线程最终对val的自加结果一样的情况。

轻量同步——synchronized

上述的情况,原书中一开始是通过synchronized,保证其修饰的代码在多线程调用下的同步性

上述代码:

public synchronized int getNextVal() {
        return ++val;
    }

你看那个人好像一条狗啊

Read Next

ZK-一致性协议