Java在两个线程之间共享一个变量

Dav*_*ave 17 java concurrency multithreading

我有两个主题.一个调用修改变量的类的update方法.另一个调用读取变量的类的update方法.只有一个线程写入,一个(或多个)线程读取该变量.由于我不熟悉多线程,因此我需要在并发性方面做些什么?

public class A
{
    public int variable; // Does this need to be volatile?
       // Not only int, could also be boolean or float.
    public void update()
    {
        // Called by one thread constantly
        ++variable;
        // Or some other algorithm
        variable = complexAlgorithm();
    }
}

public class B
{
    public A a;
    public void update()
    {
        // Called by another thread constantly
        // I don't care about missing an update
        int v = a.variable;
        // Do algorithm with v...
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢,

hid*_*isk 17

如果有一个且只有一个写入variable您的线程可以通过它来实现volatile.否则请看答案AtomicInteger.

volatile在只有一个写入线程的情况下才有效,因为只有一个写入线程,所以它始终具有正确的值variable.


Jon*_*man 9

在这种情况下,我将使用AtomicInteger,但是通用的答案是对变量的访问应该由synchronized块保护,或者使用java.util.concurrent包的另一部分.

几个例子:

使用同步

public class A {
    public final Object variable;
    public void update() {
        synchronized(variable) {
            variable.complexAlgorithm();
        }
    }
}

public class B {
    public A a;
    public void update() {
        sychronized(a.variable) {
            consume(a.variable);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用java.util.concurrent

public class A {
    public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public final Object variable;
    public void update() {
        lock.writeLock().lock();
        try {
            variable.complexAlgorithm();
        } finally {
            lock.writeLock().unlock();
        }
    }
}

public class B {
    public A a;
    public void update() {
        a.lock.readLock().lock();
        try {
            consume(a.variable);
        } finally {
            a.lock.readLock().unlock();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


jus*_*tkt 8

不仅variable如此volatile,而且您还希望通过某种同步保护您的update函数,因为它不是原子调用.毕竟,它只是语法糖++variable

variable = variable + 1;
Run Code Online (Sandbox Code Playgroud)

这不是原子的.

您还应该将任何读取变量的调用包装在某种中.

或者,使用AtomicInteger.这是为了这种事情(仅用于整数运算).

public class A
{
    // initially had said volatile wouldn't affect this variable because
    // it is not a primitive, but see correction in comments
    public final AtomicInteger variable; // see comments on this issue of why final
    public void update()
    {
        // Called by one thread constantly
        variable.getAndIncrement(); // atomically adds one
    }
    public int retrieveValue()
    {
        return variable.get(); // gets the current int value safely
    }
}

public class B
{
    public A a;
    public void update()
    {
        // Called by another thread constantly
        int v = a.retrieveValue();
        // Do algorithm with v...
    }
}
Run Code Online (Sandbox Code Playgroud)

对于更复杂的算法,如您最近的编辑所假设,使用同步或锁定.

  • 你的评论"易变不会影响这一点,它不是一个原始的"是误导.它与该字段是否具有主要性无关,而与"变量"不再被重新分配这一事实有关.在这里建议制作`variable` final. (2认同)

b_e*_*erb 5

使用AtomicIntegersynchronize访问要安全。