java中,synchronized和volatile都可以防止指令重排序,现在来验证一下其实际效果。
如下代码所示,进行测试1:两个线程,一个执行批量赋值操作,另外一个检测批量赋值操作是否乱序执行。
测试结果:确实会出现了乱序执行的情况。
/** * 指令重排序测试 * * @author zhangxz * @date 2019-11-17 16:40 */ public class CmdReorderTest { private static int a = 0; private static int b = 0; private static int c = 0; private static int d = 0; private static int e = 0; private static int f = 0; private static int g = 0; private static int h = 0; public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 500000; i++) { //join可以保证线程a b都执行完成之后,再继续下一次循环 ThreadA threadA = new ThreadA(); threadA.start(); ThreadB threadB = new ThreadB(); threadB.start(); threadA.join(); threadB.join(); //清空数据,便于测试 a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; g = 0; h = 0; } } static class ThreadA extends Thread { @Override public void run() { a = 1; b = 1; c = 1; d = 1; e = 1; f = 1; g = 1; h = 1; } } static class ThreadB extends Thread { @Override public void run() { if (b == 1 && a == 0) { System.out.println("b=1"); } if (c == 1 && (a == 0 || b == 0)) { System.out.println("c=1"); } if (d == 1 && (a == 0 || b == 0 || c == 0)) { System.out.println("d=1"); } if (e == 1 && (a == 0 || b == 0 || c == 0 || d == 0)) { System.out.println("e=1"); } if (f == 1 && (a == 0 || b == 0 || c == 0 || d == 0 || e == 0)) { System.out.println("f=1"); } if (g == 1 && (a == 0 || b == 0 || c == 0 || d == 0 || e == 0 || f == 0)) { System.out.println("g=1"); } if (h == 1 && (a == 0 || b == 0 || c == 0 || d == 0 || e == 0 || f == 0 || g == 0)) { System.out.println("h=1"); } } } }
测试2:把上面代码的所有静态变量,都使用volatile修饰
测试结果:不再出现有乱序执行的结果,可以推测是volatile保证了指令执行的有序性,不会被重排序。
如下代码所示,进行测试3:在上面的批量赋值操作,以及批量检测操作,两个操作,都加上锁,比如ReentrantLock,或者synchronized
测试结果:不再出现有乱序执行的结果,可以推测加锁,也可以保证指令执行的有序性。其实这个可以理解为互斥访问的特性,保证了有序性。
/** * 指令重排序测试 * * @author zhangxz * @date 2019-11-17 16:40 */ public class CmdReorderTest { private static int a = 0; private static int b = 0; private static int c = 0; private static int d = 0; private static int e = 0; private static int f = 0; private static int g = 0; private static int h = 0; /* private static volatile int a = 0; private static volatile int b = 0; private static volatile int c = 0; private static volatile int d = 0; private static volatile int e = 0; private static volatile int f = 0; private static volatile int g = 0; private static volatile int h = 0; */ private static ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 500000; i++) { //join可以保证线程a b都执行完成之后,再继续下一次循环 ThreadA threadA = new ThreadA(); threadA.start(); ThreadB threadB = new ThreadB(); threadB.start(); threadA.join(); threadB.join(); //清空数据,便于测试 a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; g = 0; h = 0; } } static class ThreadA extends Thread { @Override public void run() { lock.lock(); try { a = 1; b = 1; c = 1; d = 1; e = 1; f = 1; g = 1; h = 1; } finally { lock.unlock(); } } } static class ThreadB extends Thread { @Override public void run() { lock.lock(); try { if (b == 1 && a == 0) { System.out.println("b=1"); } if (c == 1 && (a == 0 || b == 0)) { System.out.println("c=1"); } if (d == 1 && (a == 0 || b == 0 || c == 0)) { System.out.println("d=1"); } if (e == 1 && (a == 0 || b == 0 || c == 0 || d == 0)) { System.out.println("e=1"); } if (f == 1 && (a == 0 || b == 0 || c == 0 || d == 0 || e == 0)) { System.out.println("f=1"); } if (g == 1 && (a == 0 || b == 0 || c == 0 || d == 0 || e == 0 || f == 0)) { System.out.println("g=1"); } if (h == 1 && (a == 0 || b == 0 || c == 0 || d == 0 || e == 0 || f == 0 || g == 0)) { System.out.println("h=1"); } } finally { lock.unlock(); } } } }