Java 并发编程之 happens-before 7 条规则

Java juc 大约 3121 字

定义

规定了对共享变量的写操作对其他线程的读操作可见。

它是可见性与有序性的一套规则总结。

synchronized

假设t1先执行:t1线程解锁m前对x变量的写,对于对m加锁的t2线程,x变量的读可见。

输出:10

public class SyncDemo {

    static int x;
    static final Object m = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (m) {
                x = 10;
            }
        }, "t1").start();

        new Thread(() -> {
            synchronized (m) {
                System.out.println(x);
            }
        }, "t2").start();
    }

}

volatile

假设t1先执行:t1线程对volatile变量x的写,对于t2线程对变量x的读可见。

输出:10

public class VolatileDemo {

    volatile static int x;

    public static void main(String[] args) {
        new Thread(() -> {
            x = 10;
        }, "t1").start();

        new Thread(() -> {
            System.out.println(x);
        }, "t2").start();
    }

}

线程 start 前

线程start前对变量x的写,当该线程启动后,在该线程中对变量x的读可见。

public class BeforeThreadStartDemo {

    static int x;

    public static void main(String[] args) {
        x = 10;

        new Thread(() -> {
            System.out.println(x);
        }, "t1").start();
    }

}

线程结束后

t1线程结束前对变量的写,当其他线程得知t1线程结束运行后的读可见。

public class AfterThreadExecuteDemo {
    static int x;

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            x = 10;
        }, "t1");
        t1.start();

        t1.join();
        System.out.println(x);
    }

}

线程 interrupt

线程t1打断线程t2前对变量x的写,对于其他线程得知t2被打断后对变量x的读可见(示例中的其他线程指的是是main线程和t2线程)。

public class ThreadInterruptDemo {

    static int x;

    public static void main(String[] args) {
        Thread t2 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("t2#" + x);
                    break;
                }
            }
        }, "t2");
        t2.start();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            x = 10;
            t2.interrupt();
        }, "t1").start();

        while (!t2.isInterrupted()) {
            Thread.yield();
        }
        System.out.println("main#"+ x);
    }

}

默认值

对于默认值的写(0falsenull),对其他线程对该变量的读可见。

public class DefaultValueDemo {

    static int x = 10;
    static boolean y = true;
    static Object z = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println(x);
            System.out.println(y);
            System.out.println(z);
        }, "t1").start();
    }

}

传递性

如果x hb -> y,并且y hb -> z,那么有x hb -> z,配合volatile的防止指令重排。

// HB: HappenBefore
public class HBDemo {

    volatile static int x;
    static int y;

    public static void main(String[] args) {
        new Thread(() -> {
            y = 20;
            x = 10;
        }, "t1").start();

        new Thread(() -> {
            System.out.println("y#" + y);
            System.out.println("x#" + x);
        }, "t2").start();
    }

}
阅读 50 · 发布于 2021-09-28

————        END        ————

扫描下方二维码关注公众号和小程序↓↓↓

扫描二维码关注我
昵称:
随便看看 换一批