先行发生八大原则(个人理解)

总结来源于《深入理解JVM虚拟机》

  1. 程序次序规则(Program Order Rule) : 在一个线程内, 按照控制流顺序, 书写在前面的操作先行发生于书写在后面的操作;
  2. 管程锁定规则(Monitor Lock Rule) : 一个unlock操作先行发生于后面对同一个锁的lock操作。 这里必须强调的是“同一个锁”, 而“后面”是指时间上的先后
  3. volatile变量规则(Volatile Variable Rule) : 对一个volatile变量的写操作先行发生于后面对这个变量的读操作, 这里的“后面”同样是指时间上的先后
  4. 线程启动规则(Thread Start Rule) : Thread对象的start()方法先行发生于此线程的每一个动作
  5. 线程终止规则(Thread Termination Rule) : 线程中的所有操作都先行发生于对此线程的终止检测, 我们可以通过Thread::join()方法是否结束、 Thread::isAlive()的返回值等手段检测线程是否已经终止执行;
  6. 线程中断规则(Thread Interruption Rule) : 对线程interrupt()方法的调用先行发生于被中断线程代码检测到中断事件的发生, 可以通过Thread::interrupted()方法检测到是否有中断发生;
  7. 对象终结规则(Finalizer Rule) : 一个对象的初始化完成(构造函数执行结束) 先行发生于它的finalize()方法的开始;
  8. 传递性(Transitivity) : 如果操作A先行发生于操作B, 操作B先行发生于操作C, 那就可以得出操作A先行发生于操作C的结论。

代码中包含join、yield、DaemonThread 故可能与八大原则有差异

public class MyTest {
    public static void main(String[] args) {
        // 設置一个钩子线程,在JVM退出时输出日志
        Runtime.getRuntime().addShutdownHook(
                new Thread(() -> System.out.println("JVM 退出成功!")));
        /**
         * 守护线程运行中,它的存在与否不会关系到JVM退出
         * 换句话说就是:线程分用户线程和非用户线程(如守护线程),只要用户线程存活,那么JVM就不会退出
         * 守护线程拥有自动结束自己生命周期的特性,而非守护线程不具备这个特点。jvm中的垃圾回收线程就是典型的守护线程,
         */
        Thread daemonThread = new Thread(() -> {
            System.out.println("守護綫程運行中");
            try {
                // 守护线程休眠10s
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        daemonThread.setDaemon(true);
        daemonThread.start();

        long startTime = System.currentTimeMillis();
        A a = A.getInstance();
        Thread t1 = new Thread(() -> {
            // 线程让步,但是并不代表别的线程一定会在它之前获取CPU执行权,而且如果持有锁的话,是不会释放当前锁的,
            // 与wait不同的是,wait会进入阻塞状态,并且会释放当前持有的锁。
            Thread.yield();
            a.method1();
            System.out.println(Thread.currentThread().getName() + "线程执行完毕,此时 var = " + a.var);
        }, "t1 ==> ");
        t1.start();

        Thread t2 = new Thread(() -> {
            Thread innerThread = new Thread(() -> {
                try {
                    TimeUnit.SECONDS.sleep(new Random().nextInt(3));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                a.method3();
                System.out.println(Thread.currentThread().getName() + "线程执行完毕,此时 var = " + a.var);
            }, "innerThread ==> ");
            innerThread.start();
            try {
                innerThread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 执行这个方法必须等达 innerThread 执行完毕,所以 var的值一定是method3()的值
            a.method2();
            System.out.println(Thread.currentThread().getName() + "线程执行完毕,此时 var = " + a.var);
        }, "t2 ==> ");
        t2.start();

        // 此时存活的线程数为:gc、main以及自定义的守护线程
        while (Thread.activeCount() != 3) {
            Thread.yield();
        }
        // JVM退出的时候,实际线程执行的时间远远小于守护线程的存活时间
        System.out.println("所有的任务执行完毕!执行时间 = " + (System.currentTimeMillis() - startTime));
    }
}

class A {
    public int var;

    private static A a = new A();

    private A() {
    }

    public static A getInstance() {
        return a;
    }

    public synchronized void method1() {
        var = 3;
    }

    public synchronized void method2() {
        int b = var;
    }

    public void method3() {
        //注意这里和method1 method2 用的可不是同一个锁哦
        synchronized (new A()) {
            var = 4;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值