Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当有';s易失性字段和非易失性字段的混合_Java_Multithreading_Volatile_Happens Before - Fatal编程技术网

Java 当有';s易失性字段和非易失性字段的混合

Java 当有';s易失性字段和非易失性字段的混合,java,multithreading,volatile,happens-before,Java,Multithreading,Volatile,Happens Before,我试图理解当存在易失性字段和非易失性字段的混合时,易失性字段的行为 假设有1个WriteThread和5个ReadThread线程,它们更新/读取SharedObject ReadThreads从一开始调用方法waitToBeStopped(),WriteThread在1秒后调用方法stop() public class SharedObject { volatile boolean stopRequested = false; int a = 0, b = 0, c = 0;

我试图理解当存在易失性字段和非易失性字段的混合时,易失性字段的行为

假设有1个WriteThread和5个ReadThread线程,它们更新/读取SharedObject

ReadThreads从一开始调用方法
waitToBeStopped()
,WriteThread在1秒后调用方法
stop()

public class SharedObject {

    volatile boolean stopRequested = false;
    int a = 0, b = 0, c = 0;
    int d = 0, e = 0, f = 0;

    // WriteThread calls this method
    public void stop() {
        a = 1;  
        b = 2;  
        c = 3;
        stopRequested = true;
        a = 4;  
        b = 5;
        c = 6; 
        d = 7;
        e = 8;
        f = 9;
    }

    // ReadThread calls this method
    public void waitToBeStopped() throws Exception {
        
        while(!stopRequested) {
        }
        System.out.println("Stopped now.");

        System.out.println(a + " " + b + " " + c + " " + d + " " + e + " " + f);
    }
}
当这个程序结束时,输出是这样的。即使我尝试了100多个ReadThreads,结果也总是一样的

Stopped now.
Stopped now.
Stopped now.
Stopped now.
Stopped now.
4 5 6 7 8 9
4 5 6 7 8 9
4 5 6 7 8 9
4 5 6 7 8 9
4 5 6 7 8 9
Q1。有人能解释为什么它总是返回4,5,6,7,8,9而不是1,2,3,0,0,0吗?

我对恋爱前发生的事情的理解是这样的:

  • WriteThread写入
    a=1、b=2、c=3
    发生在WriteThread写入
    stopRequested
  • WriteThread写入
    stopRequested
    发生在写入
    a=4、b=5、c=6、d=7、e=8、f=9之前
  • WriteThread写入
    stopRequested
    发生在读取线程读取
    stopRequested
  • 读线程读取
    stopRequested
    发生在读线程读取
    a、b、c、d、e、f之前
从这4个陈述中,我无法得出这样的一个

  • WriteThread写入
    a=4,b=5,c=6,d=7,e=8,f=9
    发生在读线程读取
    a,b,c,d,e,f
下面是代码的另一部分(如果有帮助):

public class App {
    public static void main(String[] args) throws Exception {
        SharedObject sharedObject = new SharedObject();

        for(int i =0 ; i < 5; i++) {
            Runnable rThread = new ReadThread(sharedObject);
            new Thread(rThread).start();
        }
        Runnable wThread = new WriteThread(sharedObject);
        
        new Thread(wThread).start();        

    }
}

您假设在
stopRequested=true之后写入不保证对读者可见是正确的。写入程序不保证写入到共享缓存/内存中,而这些缓存/内存对读卡器是可见的。它只需将它们写入本地缓存,读卡器就看不到更新的值

Java语言保证了可见性,例如,当您使用可变变量时。但它不能保证非易失性变量的更改对其他线程不可见。这样的书写仍然可以看到,就像在您的案例中一样。JVM实现、处理器的内存一致性模型和其他方面都会影响可见性


请注意,JLS和“发生在之前”关系是一个规范。JVM实现和硬件通常比JLS指定的做得更多,这可能会导致写入的可见性,而JLS不必看到这些写入不保证对读者可见是正确的。写入程序不保证写入到共享缓存/内存中,而这些缓存/内存对读卡器是可见的。它只需将它们写入本地缓存,读卡器就看不到更新的值

Java语言保证了可见性,例如,当您使用可变变量时。但它不能保证非易失性变量的更改对其他线程不可见。这样的书写仍然可以看到,就像在您的案例中一样。JVM实现、处理器的内存一致性模型和其他方面都会影响可见性


请注意,JLS和“发生在之前”关系是一个规范。JVM实现和硬件通常比JLS指定的做得更多,这会导致写操作的可见性,而JLS不必看到这些写操作。

Hey!你能把整个测试课也发出来吗?你有没有考虑过设置6个整数可能比打印到控制台要快得多?嘿@akuzminykh,我也分享了其他的类。嗯,我不明白的是,如果4,5,6,7,8,9是在volatile字段(stopRequested)被写入之后写入的,那么更改是如何进行的?这里的顺序不重要吗?嘿!你能把整个测试课也发出来吗?你有没有考虑过设置6个整数可能比打印到控制台要快得多?嘿@akuzminykh,我也分享了其他的类。嗯,我不明白的是,如果4,5,6,7,8,9是在volatile字段(stopRequested)被写入之后写入的,那么更改是如何进行的?这里的订单不重要吗?非常感谢!这很有帮助。这些行为很难测试。@Ryan True。这就是为什么很难进行正确的同步。没有指标时很难发现问题。。突然,它会出现在另一台机器上,或者在你意想不到的时候。这就是为什么对
volatile
的实际功能有很好的理解是如此重要。查看更多详细信息。非常感谢!这很有帮助。这些行为很难测试。@Ryan True。这就是为什么很难进行正确的同步。没有指标时很难发现问题。。突然,它会出现在另一台机器上,或者在你意想不到的时候。这就是为什么对
volatile
的实际功能有很好的理解是如此重要。查看更多详细信息。
public class WriteThread implements Runnable {

    private SharedObject sharedObject;
    
    public WriteThread(SharedObject sharedObject) {
        this.sharedObject = sharedObject;
    }
    
    public void run() {
        try {
            TimeUnit.SECONDS.sleep(1);
            sharedObject.stop();
                        
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
public class ReadThread implements Runnable {

    private SharedObject sharedObject;
    
    public ReadThread(SharedObject sharedObject) {
        this.sharedObject = sharedObject;
    }
    
    public void run() {
        try {
            sharedObject.waitToBeStopped();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }   
}