【问题标题】:Are primitive datatypes thread-safe in JavaJava中的原始数据类型是线程安全的吗
【发布时间】:2012-02-14 14:38:50
【问题描述】:

intshort 这样的原始数据类型在Java 中是线程安全的吗?我已经执行了以下代码,但有时看不到预期的结果 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

【问题讨论】:

  • 不,它们不是线程安全的。如果你只打算阅读,你应该考虑成为会员volatile。如果你打算从不同的线程读写它,你应该把它设为synchronized

标签: java thread-safety primitive


【解决方案1】:

它们不安全的三种方式:

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 关键点是,如果一个原语被定义为对象实例的一部分,那么该原语将在堆上,而不是线程安全的。
    • 这很奇怪。 oracle 文档实际上说原始类型访问对于 int 是原子的:docs.oracle.com/javase/tutorial/essential/concurrency/…
    • @Parvin,除了 long 和 double,基本类型保证是原子的。如果您正在读取或写入该值,则该操作的线程安全。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:
      1. 要在多线程环境中读取/写入值,程序应具有适当的同步或锁定以防止数据竞争。它与访问哪种数据类型无关。在理想的世界中,我们不应该共享任何东西或只共享不可变对象,这始终是线程安全的。

      2. 理论上,根据https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.7,甚至不能保证 long/double 的原子性 但是,实现往往是原子的,以下代码在我的环境(64位ubuntu 18.04,英特尔64位CPU,Oracle JDK 8)中打印出任何带或不带volatile关键字的内容,因此在这种情况下它是原子的,我想这适用于所有英特尔/AMD 64 处理器。 我们也可以对 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);
          }
      }
      

      【讨论】:

      • 欢迎终于在stackoverflow上发帖。请详细说明It 开始您的帖子:问题的代码显示仅针对inT 的并发写入,既不是double 也不是long
      • LongThreadSafe.value 是多线程读写的值。已经用~~~附上了代码,谢谢
      • 仍然不清楚你的帖子开头的It 指的是什么:the question 的一个明确问题询问types - 要引用这些类型,它必须成为他们
      • 你说得对,我更新了答案以涵盖线程安全和类型
      猜你喜欢
      • 1970-01-01
      • 2018-01-07
      • 2015-05-10
      • 2017-05-27
      • 2019-04-23
      • 2021-12-16
      • 2011-03-07
      • 1970-01-01
      相关资源
      最近更新 更多