原始数据类型是Java中的线程安全的

时间:2012-02-14 14:38:50

标签: java thread-safety primitive

原始数据类型是int& Java中的short线程安全吗?我已经执行了以下代码,有时无法看到预期的结果500。

public class SampleThree extends Thread
{
    static long wakeUpTime = System.currentTimeMillis() + (1000*20);
    static int inT;
    public static void main(String args[])
    {
        System.out.println("initial:" + inT);
        for(int i=0; i<500; i++)
            new SampleThree().start();
        try {
            Thread.sleep(wakeUpTime - System.currentTimeMillis() + (1000*30));
            System.out.println("o/p:" + inT);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }

    public void run()
    {
        try {
            long s = wakeUpTime - System.currentTimeMillis();
            System.out.println("will sleep ms: " + s);
            Thread.sleep(s);
            inT++; // System.out.println(inT);
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }
}

这里同时500个线程将更新int变量inT。等待并发更新完成后的主线程打印inT值。

查找类似示例here

4 个答案:

答案 0 :(得分:54)

他们有三种不安全的方式:

  • longdouble甚至不能保证以原子方式更新(您可以看到来自不同线程的写入的一半)
  • 内存模型不保证您会在另一个线程中看到来自一个线程的最新更新,而不会产生额外的内存障碍
  • 无论如何,递增变量的行为都不是原子的

使用AtomicInteger等进行线程安全操作。

答案 1 :(得分:9)

原始类型不是线程安全的。查看this教程。

答案 2 :(得分:4)

我建议在java.util.concurrent.atomic中使用类。它们专为线程安全而设计,在某些情况下,JVM可以利用硬件功能进行优化。

答案 3 :(得分:0)

  1. 要在多线程环境中读取/写入值,程序应具有适当的同步或锁定功能,以防止数据争用。它与访问哪种数据类型无关。在理想的世界中,我们应该不共享任何内容,或者仅共享不可变的对象,这始终是线程安全的。

  2. 从理论上讲,根据https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7,甚至不能保证它对于long / double来说是原子的 但是,实现倾向于原子性的,以下代码在我的环境中(不管有没有)volatile关键字(64位ubuntu 18.04,英特尔64位CPU,Oracle JDK 8)都不会打印出任何内容,因此在这种情况下它是原子性的,我想这适用于所有英特尔/ AMD 64 CPU。 我们也可以对double进行相同的操作,尽管构造具有某些属性要检查的double值有点棘手。

public class LongThreadSafe {

    // multiple threads read and write this value.
    // according to the java spec, only volatile long is guaranteed to be atomic
    private static long value = 0;

    private static final int max = (1 << 30) - 1;
    private static final int threadCount = 4;
    static ExecutorService executorService = Executors.newFixedThreadPool(threadCount);

    static CyclicBarrier barrier = new CyclicBarrier(threadCount);

    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i < threadCount; i++) {
            executorService.submit(() -> {
                try {
                    // all threads start to work at the same time
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                for (int j = 1; j < max; j++) {
                    // read value into v2
                    long v2 = value;
                    // check v2 
                    int low = (int) v2;
                    int high = (int) (v2 >> 32);
                    if ((high << 1) != low) {
                        System.out.println("invalid number found high=" + high + ", low=" + low);
                    }
                    // write LongThreadSafe.value again 
                    LongThreadSafe.value = ((long) j << 32) | (long) (j << 1);


                }
            });
        }
        executorService.shutdown();
        executorService.awaitTermination(10, TimeUnit.MINUTES);
    }
}