java变量本身是否安全?更新变量时?

时间:2016-02-29 04:19:04

标签: java multithreading synchronization thread-safety volatile

假设我有两个线程更新一个对象,一个线程从该对象读取而没有同步。显然,这是运行条件。但是,我想知道变量本身是否只能部分写入。

public class CommonObject extends Object
{
    static int memberVar=-1;
}

public class Input1Thread extends Thread
{   
    public void run()   
    {
        while(true)
            CommonObject.memberVar = 1
    }
}

public class Input2Thread extends Thread
{   
    public void run()   
    {
        while(true)
            CommonObject.memberVar = 2;
    }
}

public class OutputThread extends Thread
{   
    public void run()   
    {
        while(true)
            System.out.println("CommonObject.memberVar"+ CommonObject.memberVar);
    }
}  

我会假设打印出来的值也是2或1.但是,我想知道变量是否可能设置为中途?

我使用了原语作为一个例子,但如果不同的话,我也希望对象也能得到答案。

3 个答案:

答案 0 :(得分:3)

这取决于变量的类型。

doublelong s(Java中的两个64位类型)如果不是volatile,则允许进行单词撕除,而所有其他类型(可能永远不会撕裂。单词撕裂会给你你担心的行为:一些字节来自旧值,其中一些是来自新值,而整体结果是一个既不是旧的也不是旧的值新。

这在JLS 17.7中指定:

  

出于Java编程语言内存模型的目的,对非易失性long或double值的单次写入被视为两个单独的写入:每个32位一半写入一次。这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位。

     

volatile和long值的写入和读取始终是原子的。

     

对引用的写入和读取始终是原子的,无论它们是作为32位还是64位实现。

当然,引入数据竞赛引入了许多问题;但是你的问题专门针对单词撕裂,所以我只是在这里解决,除非要注意"只是因为你可以,并不意味着你应该这样做。"您应该小心分析您拥有的每个数据竞争,并证明它是良性的(因为它们中的一些 - 就像String.hashCode'它的值的缓存)。

答案 1 :(得分:0)

查看AtomicInteger类和线程上的java教程以获取示例。还有javadoc。

https://docs.oracle.com/javase/tutorial/essential/concurrency/

答案 2 :(得分:-1)

对于原语是安全的但对Object不安全。例如,对象A有两个变量int a,b,如果你试图在两个不同的线程中改变它们的值,你会发现两个线程的值都是可能有时会同时出现。

相关问题