2012-02-14 92 views
26

原始数据类型是int & short在Java中是线程安全的吗?我执行了下面的代码,有些时候看不到预期的结果500。原始数据类型在Java中是线程安全的

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

+9

不,它们不是线程安全的。如果你只打算阅读,你应该考虑让成员变成“volatile”。如果你打算从不同的线程读取和写入它,你应该使它成为'同步的' – 2012-02-14 14:41:34

回答

45

有三种方式他们没有安全:

  • longdouble甚至不保证用原子方式更新(你可以看到一半写的从不同的线程)
  • 内存模型不保证你会看到从另一个线程中的一个线程的最新更新,没有额外的内存障碍
  • 增量变量的行为不是原子无论如何

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

4

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

10

基本类型不是线程安全的。检查this教程。

+0

关键的一点是,如果一个原语被定义为一个对象实例的一部分,那么这个原语将会在堆上,而不是线程安全。 – okwap 2015-02-09 13:56:18

+2

这很奇怪。 oracle文档实际上说原始类型访问对int来说是原子的:https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html – Yamcha 2017-05-22 14:47:12

+1

@Parvin,除了long和double之外,原始类型保证是原子。如果您正在读取或写入该值,则其线程可以安全地执行该操作。 – Pacerier 2017-09-20 02:39:31