用于Java中读写操作的易失性变量

问题描述 投票:0回答:1

我正在学习Java中的volatile和synchronized,我发现synchronized用于读取 - 修改 - 写入操作,如x++,而volatile用于读写操作。我想问你2个问题。如何看待读写操作?

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

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。那么这不是一个读 - 修改 - 写操作吗?谢谢!

java multithreading concurrency synchronized volatile
1个回答
3
投票

声明stop = true;不是“读写”操作,而只是写操作。它根本不读取变量的旧值。如果stop以前的值是true,那么该声明没有效果,没有注意到差异。

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

对于你的boolean变量,“read-modify-write”操作可能看起来像

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();
        }
    }
}

正好一个线程将负责发送停止信号。

© www.soinside.com 2019 - 2024. All rights reserved.