Java多线程——happens-before规则

happens-before规则

happens-before规定了对共享变量的写操作对其他线程读操作可见,它是可见性与有序性的一套规则总结,在此规则之外JMM(Java Memory Model, JMM)并不能保证变量的可见性。

什么是JMM可参考CSDN的一篇文章:JMM概述

规则一

synchronized保证变量的可见性

    int x = 0;
    static Object lock = new Object();

    public void test() {
        new Thread(() -> {
            synchronized (lock) {
                x = 10;
            }
        }, "t1").start();

        new Thread(() -> {
            synchronized (lock) {
                log.info("{}", x);
            }
        }, "t2").start();
    }

规则二

volatile关键字修饰变量

    volatile int x = 0;

    public void test() {
        new Thread(() -> {
            x = 10;
        }, "t1").start();

        new Thread(() -> {
            log.info("{}", x);
        }, "t2").start();
    }

规则三

线程start()之前对变量改写,启动线程后,对该变量读可见

在线程启动之前,共享变量的值已经被同步到了主存中

    volatile int x = 0;

    public void test() {
        x = 10;
        new Thread(() -> {
            log.info("{}", x);
        }, "t2").start();
    }

规则四

线程执行时对共享变量的写操作,在线程结束后,对于其他线程来说是读可见(如使用thread.isAlive或者thread.join等待该线程的执行结束)

    int x = 0;

    public void test() throws InterruptedException {

        Thread t1 = new Thread(() -> {
            x = 10;
        }, "t1");
        t1.start();

        t1.join();
        log.info("{}", x);
    }

规则五

打断线程之前的成员变量写操作,对于被打断线程以及其他得知被打断线程被打断后,x的写操作是满足可见性的

package com.leolee.multithreadProgramming;


import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName Test
 * @Description: TODO
 * @Author LeoLee
 * @Date 2020/12/1
 * @Version V1.0
 **/
@Slf4j
public class Test {

    int x = 0;
    static Object lock = new Object();

    public void test() throws InterruptedException {
        
        Thread t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    log.info("{}", x);
                    break;
                }
            }
        }, "t1");
        t1.start();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            x = 10;
            t1.interrupt();
        }, "t2").start();

        while (!t1.isInterrupted()) {
            Thread.yield();
        }
        log.info("{}", x);
    }

    public static void main(String[] args) throws InterruptedException {
        Test test = new Test();
        test.test();
    }
}

规则六

对于变量的默认值,对于其他线程是读可见的

规则七

volatile写屏障的传递性

    volatile int x;
    int y;

    public void test() {
        new Thread(() -> {
            y = 20;
            x = 10;
            //写屏障
        }, "t1").start();

        new Thread(() -> {
            //对于写屏障之前的写操作,都将被同步到主存中。y和x都是对t2线程可见的
            log.info("{}", y);
            log.info("{}", x);
        }, "t2").start();
    }

 

你可能感兴趣的:(#,JAVA多线程并发编程,volatile,可见性,屏障,happens,before)