【问题标题】:Volatile variable for read-write operations in JavaJava中用于读写操作的可变变量
【发布时间】:2019-03-18 18:23:28
【问题描述】:

我正在学习 Java 中的 volatile 和 synchronized,我看到 synchronized 用于像 x++ 这样的读-修改-写操作,而 volatile 用于读写操作。我想问你两个问题。读写操作看起来如何?

对于第二个问题,我有这个代码:

public class StopThread {
    private static volatile boolean stop;

    public static void main(String[] args) throws InterruptedException { 

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (!stop) {
                    System.out.println("In while...");
                }
            }

        }).start();

        TimeUnit.SECONDS.sleep(1); 
        stop = true;
    }

}

而且我不明白为什么这是一个读写操作,因为 stop 变量将从 false 修改为 true。那么这不是一个读-修改-写操作吗?谢谢!

【问题讨论】:

  • “修改”和“写入”有什么区别?
  • 在这种情况下,两个线程都将使用共享变量来执行完全不同的操作。由于将使用共享变量,因此您需要对其进行同步。一个线程将读取变量,另一个线程将对其进行修改。随心所欲地调用它。
  • IMO 你问错问题了。线程之间共享数据的问题在于,为了有意义地更新某些数据对象,通常需要一个线程暂时将对象置于某种无效或错误状态。通过正确使用synchronized,您可以防止其他线程看到该无效/错误状态。 volatile 关键字根本无法解决这个问题,但还有一个次要问题,volatilesynchronized 都可以帮助解决......
  • ...编译器、运行时和硬件都可以“优化”您的代码。这些优化可以假设线程之间没有数据共享,如果您的线程实际上确实共享,事情可能会出错。 volatile 关键字只是声明“这个变量是共享的”。 synchronized 关键字做了更复杂的事情:它保证当线程 A 离开 synchronized(a)... 块,然后线程 B 随后进入 synchronized(a)...(注意!相同的 a),那么线程 B 将保证看到所有内容那个线程 A 做了。

标签: java multithreading concurrency synchronized volatile


【解决方案1】:

语句stop = true; 不是“读写”操作,而只是。它根本不读取变量的旧值。如果stop之前的值是true,则语句没有作用,没有注意到差异。

“read-modify-write”操作,也称为“read-update-write”操作,意味着读取前一个值,根据它计算一个新值,并将新值写回变量的操作.此操作的问题是,当不使用特殊的原子更新构造时,在执行写入时,可能已经发生了并发更新,因此变量被基于过时的先前值的计算值覆盖.

对于您的 boolean 变量,“读取-修改-写入”操作可能看起来像

if(!stop) stop = true;

stop = !stop;

但对于第一个变体,缺少并发更新不会产生太大影响,因为如果变量已经是 true,则该语句无效。如果同时执行第二个可能会错过更新,因此,不能反映正确的翻转操作数量,但使用并发 boolean 更新进行多个状态转换通常容易出错。

“读写”操作,即中间没有“修改/更新”,将是读取旧值以供以后使用并写入不基于旧值的新值的操作。喜欢

Type old = variable;
variable = newValue;
// use old here

如果不以原子方式完成,它仍然会丢失更新。因此,这样的操作还需要不止一个volative 变量。例如。 AtomicInteger.getAndSetVarHandle.getAndSet

因此将您的示例扩展到

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

public class StopThread {
    private static volatile boolean stop;

    public static void main(String[] args) throws InterruptedException { 

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(!stop) {
                    System.out.println("In while...");
                }
            }
        }).start();
        for(int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); 
                    boolean old = stop; // broken because
                    stop = true;        // not atomic
                    System.out.println(old? "other thread was faster": "sent stop signal");
                }
            }).start();
        }
    }
}

多个线程可能认为他们发送了停止信号。

如果您将代码修复为

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;

public class StopThread {
    private static final AtomicBoolean stop = new AtomicBoolean();

    public static void main(String[] args) throws InterruptedException { 

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(!stop.get()) {
                    System.out.println("In while...");
                }
            }
        }).start();
        for(int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1)); 
                    boolean old = stop.getAndSet(true);
                    System.out.println(old? "other thread was faster": "sent stop signal");
                }
            }).start();
        }
    }
}

只有一个线程负责发送停止信号。

【讨论】:

    猜你喜欢
    • 2016-05-20
    • 2018-08-31
    • 1970-01-01
    • 2014-01-03
    • 2017-03-18
    • 1970-01-01
    • 2023-03-20
    • 2014-09-22
    • 2017-10-03
    相关资源
    最近更新 更多