并发编程之线程的有序性 |
您所在的位置:网站首页 › 线程并发性 › 并发编程之线程的有序性 |
并发编程的有序性
程序真的是按“顺序”执行的吗?为什么会存在乱序的现象(为了提高效率)乱序发生的原则(语句执行交换顺序的条件)
通过小程序认识可见性和有序性问题Volatile如何禁止指令重排序?
程序真的是按“顺序”执行的吗?
乱序的验证: public class T01_Disorder { private static int x = 0, y = 0; private static int a = 0, b = 0; public static void main(String[] args) throws InterruptedException { for (long i = 0; i public void run() { a = 1; x = b; latch.countDown(); } }); Thread other = new Thread(new Runnable() { public void run() { b = 1; y = a; latch.countDown(); } }); one.start(); other.start(); latch.await(); String result = "第" + i + "次 (" + x + "," + y + ")"; if (x == 0 && y == 0) { System.err.println(result); break; } } } }如上代码中的线程one将a的值设置为1,x的值设置为b,线程other将b的值设置为1,将y的值设置为a,然后再用CountDownLatch这个类来控制两个线程的执行,然后当x=0并且y=0的时候结束程序的运行。 输出结果如下: 如下图总结了如上代码运行的所有结果: 如上图中发现如果不打乱两线程run方法里面的语句的执行顺序的话,是不会出现x=0并且y=0的情况,只有当x=a,y=b或者x=b,y=a先执行才会出现x=0并且y=0的情况那么则说明两线程的run方法里面的语句执行顺序被打乱了。 为什么会存在乱序的现象(为了提高效率)
1、前后两条语句没有依赖关系,不影响单线程的最终一致性(as-if-serial) 如x=1之后执行x++这两条语句互有依赖关系 但是如上代码x=b,a=1这样是没有互相的依赖关系的。 通过小程序认识可见性和有序性问题 public class NoVisibility { private static boolean ready = false; private static int number; private static class ReaderThread extends Thread { @Override public void run() { while (!ready) { Thread.yield(); } System.out.println(number); } } public static void main(String[] args) throws Exception { Thread t = new ReaderThread(); t.start(); number = 42; ready = true; t.join(); } }如上代码有两个问题: 1、不满足ready线程之间的可见性 2、有序性问题(打印可能是0,由于number=42和ready=true没有前后的依赖关系,所以可能会交换顺序,导致先读取到ready,然后直接输出number=0) 再看如下例子: 1、首先了解对象的创建过程: 如上代码可能输出num=0,所以一般来说尽量不要在构造方法里面去new线程并将它启动,因单独写一个方法让它启动。 如下所示: public class T03_ThisEscape { private int num = 8; Thread t; public T03_ThisEscape() { new Thread(() -> System.out.println(this.num) ); } public void start(){ t.start(); } public static void main(String[] args) throws Exception { new T03_ThisEscape(); System.in.read();//让主程序不结束 } } Volatile如何禁止指令重排序?Hapens Before原则(JVM规定重排序必须遵守的规则) JVM内存屏障:其中load叫读,store叫写
volatile底层实现: 1:volatile i 2:通过编译成class文件变成 ACC_VOLATILE 3:JVM的内存屏障 屏障两边的指令不可以重排,并保障有序 happens-before as-if-serial 4:hotspot实现 进入到bytecideinterpreter.cpp |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |