Happens-before 是啥

Happens-before 是啥

官网Happens-before
The results of a write by one thread are guaranteed to be visible to a read by another thread only if the write operation happens-before the read operation.
The synchronized and volatile constructs, as well as the Thread.start() and Thread.join() methods, can form happens-before relationships.:

Happens-before就是 保证一个线程执行的操作(写)对不同线程中的另一个操作(读)可见。

  • Each action in a thread happens-before every action in that thread that comes later in the program’s order.
    一个线程中,程序顺序执行每一步操作;前一步对后一步可见。 (Rule 1)
  • An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.
    对一个锁的unlock操作先于后续对此锁的lock操作;前一步对后一步可见。(Rule 2)
  • A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.
    volatile 属性写入操作先于后续对此属性的读取操作;前一步对后一步可见。(Rule 3)
  • A call to start on a thread happens-before any action in the started thread.
    子线程启动前的任何主线程操作,都先于子线程执行;前一步对后一步可见。 (Rule 4)
  • All actions in a thread happen-before any other thread successfully returns from a join on that thread.
    一个线程的所有操作先于对其他线程对此线程的成功返回操作(中断,等待终止);前一步对后一步可见。 (Rule 5)

例子 适配 Rule 1, Rule 4, Rule 5

package pr.iceworld.fernando.happens.before;

public class Rule1 {

    /**
     * 主线程直接调用
     * 子线程直接调用
     * 不管谁调用,都是按顺序执行
     * @param a
     * @param b
     * @return
     */
    public int calculatePlus5(int a, int b) {
        int d = 5;
        int c = a + b + d;
        return c;
    }

    public int calculatePlus5ByNewThread(int a, int b, int threadIdTag) throws InterruptedException {
        MyThread thread = new MyThread(a, b, threadIdTag);
        System.out.println("我是主线程操作的, 子线程" + threadIdTag + "随后处理");
        thread.start();
        thread.join();
        System.out.println("子线程" + threadIdTag + "操作完了");
        return thread.getC();
    }

    private class MyThread extends Thread {
        private int a;
        private int b;
        private int c;

        private int theadIdTag;
        public MyThread(int a, int b, int theadIdTag) {
            this.a = a;
            this.b = b;
            this.theadIdTag = theadIdTag;
        }

        public void run() {
            System.out.println("我是子线程" + theadIdTag + "操作的");
            c = calculatePlus5(a, b);
        }

        public int getC() {
            return c;
        }
    }
}

测试用例

    @Test
    public void testRule1Calculate() throws InterruptedException {
        Rule1 rule1 = new Rule1();
        Random random = new Random();
        for (int i = 0; i < 1000; i++) {
            Assert.assertEquals(17, rule1.calculatePlus5(5, 7));
            Thread.sleep(random.nextInt(20));
            Assert.assertEquals(17, rule1.calculatePlus5ByNewThread(5, 7, i));
        }
    }

例子适配 Rule1, Rule 2, Rule 3, Rule 4

package pr.iceworld.fernando.happens.before;

import java.util.Arrays;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;

public class Rule2 {

    int size = 20;
    private Object[] lockObjects = new Object[size];
    int[] is = new int[size];
    private boolean[] producerStarts = new boolean[size];

    private boolean[] consumerStarts = new boolean[size];
    private boolean[] flags = new boolean[size];

    public Rule2() {
        for (int i = 0; i < size; i++) {
            is[i] = i;
            producerStarts[i] = true;
            if (producerStarts[i]) {
                consumerStarts[i] = true;
            }
            flags[i] = false;
            lockObjects[i] = new Object();
        }
    }

    final Queue<String> queue = new ArrayBlockingQueue<>(size * 4);

    public Queue<String> getQueue() {
        return queue;
    }
    public void doSynchronize() {
        Arrays.stream(is).forEach( e -> {
            Thread consumer = new Thread("consumer" + e) {
                public void run() {
                    queue.add("consumerStarts[" + e + "] = " + consumerStarts[e]);
                    while (true) {
                        synchronized (lockObjects[e]) {
                            if (flags[e]) {
                                flags[e] = false;
                                queue.add("consumer " + e + " verified the flag");
                            }
                        }
                    }
                }
            };
            consumerStarts[e] = true;
            consumer.start();
        });

        Arrays.stream(is).forEach(e -> {
            Thread producer = new Thread("producer" + e) {
                public void run() {
                    queue.add("producerStarts[" + e + "] = " + producerStarts[e]);
                    synchronized (lockObjects[e]) {
                        flags[e] = true;
                        queue.add("producer " + e + " changed flag");
                    }
                }
            };
            producerStarts[e] = true;
            producer.start();
        });

    }
}

测试用例

    @Test
    public void testRule2DoSynchronize() throws InterruptedException {
        Rule2 rule2 = new Rule2();
        rule2.doSynchronize();
        // 方便线程执行完成
        Thread.sleep(2000);
        rule2.getQueue().stream().forEach(System.out::println);
        System.out.println("done");
        System.out.println("---------------");
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值