编程语言
首页 > 编程语言> > 在Java中发生的事先机制

在Java中发生的事先机制

作者:互联网

我在Java中遇到过关于先发生机制的问题.这是一个例子:

public class MyThread extends Thread {

        int a = 0;
        volatile int b = 0;

        public void run() {


            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            read();
        }

        public void write(int a, int b) {
            this.a = a;  
            this.b = b;
        }

        public void read() {
            System.out.println(a + " " + b);
        }


    }

这是事先发生的明显例子,这是足够安全的,正如我所知道的那样. a将正确获得新值,因为它在b初始化之前.但重新排序是否意味着安全性得不到保证?我在说这个:

public void write(int a, int b) {
    this.b = b;
    this.a = a;//might not work? isn't it?
}

UPD主线程:

public class Main {

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

        MyThread t = new MyThread();
        t.start();
        t.write(1, 2);


    }
}

解决方法:

使b变为volatile并且在将值设置为a后将写入值设置为b可保证:

>如果在a之前读取b,那么
> a的值不会超过之前写入b时的值.

即,对b的写入和对b的读取充当同步点或栅栏,这意味着在从b读取之后写入的任何内容将在从b读取之后可读(如果a被写入多于一次) ,以下写入可能会或可能不会显示).

但是,您的代码现在不安全.在阅读中,您有以下表达式:

a + " " + b

在Java中,expressions are evaluated left-to-right.这意味着,将在b之前评估a.因此,读取a将完全有可能看到a的旧值,而b的读取将看到b的新值.如果你在a之前读过b,那么b的写入和读取之间的发生之前的关系将涵盖对a的写入和对a的读取.现在,它没有.

至于写入中的重新排序操作 – 这将明显消除b的排序保证对a的操作的影响,即使读取首先读取b然后读取a.

为了可视化事物,只给出b是易变的:

当前代码不保证在 – 的操作顺序 –

write a                         read a
write b --> happens before -->  read b

使用给定读取重新排序写入也不会顺序 –

                                read a
write b --> happens before -->  read b
write a

即使给定的读取是固定的,也不会按顺序排序 –

write b --> happens before -->  read b
write a                         read a

唯一安全的做法是保持当前写入并修复读取 –

write a
write b --> happens before -->  read b
                                read a

标签:java,multithreading,volatile,java-memory-model
来源: https://codeday.me/bug/20190624/1277803.html