【问题标题】:Are java variables themselves thread safe? When updating variables? [duplicate]java变量本身是线程安全的吗?更新变量时? [复制]
【发布时间】:2016-02-29 04:19:04
【问题描述】:

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

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。但是,我想知道变量是否有可能被设置到一半?

我以原语为例,但如果对象不同,我希望答案也适用于对象。

【问题讨论】:

  • 我觉得这个问答比较好。它们也更具体地用于单词撕裂。

标签: java multithreading synchronization thread-safety volatile


【解决方案1】:

这取决于变量的类型。

doubles 和 longs(Java 中的两个 64 位类型)如果不是 volatile,则允许字撕裂,而所有其他类型(包括引用)可能永远不会撕裂。字撕裂会给您带来您担心的行为:一些字节来自旧值,其中一些来自新值,总体结果是一个既不是旧值也不是新值的值。

这是在JLS 17.7中指定的:

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

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

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

当然,引入数据竞争会带来很多问题;但是你的问题是专门针对单词撕裂的,所以我只在这里解决这个问题,除了要注意“仅仅因为你可以,并不意味着你应该”。您应该仔细分析您拥有的每个数据竞争,并证明它是良性的(因为其中一些是良性的——例如 String.hashCode 对其值的缓存)。

【讨论】:

  • 很好的答案。我认为这个答案比另一个问题的答案更好。
  • 那么,如果它是 volatile 的 long 是完全安全的?
  • @GC_ 这取决于您所说的“安全”是什么意思!它不会撕裂......但数据竞争还有其他问题,比如看起来发生了乱序,或者可能根本没有被其他线程看到(如果它们被缓存在本地寄存器中)。
  • 等等,从头开始——我脑子里放了个屁,在我的评论进行到一半时,我从认为你问的是易失性物质转变为非易失性物质。是的,多头在波动时是完全安全的。 :) (当然,如果您需要以原子方式更新它们以及其他状态,那么 volatile 是不够的。)
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 对象不是变量。这个问题专门针对变量。此外,对于 all 原始类型也不安全。 JLS 明确允许 double 变量和 long 变量的更新是非原子的。 (见 yshavit 的回答)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多