java synchronized具有禁止重排序功能

1.结论

我们知道volatile关键字具有禁止指令重排序的功能,而且能保证可见性,但不能保证原子性。synchronized关键字则不仅仅能保证可见性,还能保证原子性,那么synchronized关键字是否像volatile那样具有禁止指令重排序的功能呢?答案是肯定的,synchronized具有禁止重排序功能。

2.论据出处

查找国内文档,发现基本对synchronized的描述很少提及禁止重排序的问题,大多都是在说原子性。于是查阅了国外的技术文档,其中举例说明了synchronized具有禁止重排序功能:

class Test {
    static int i = 0, j = 0;
    static void one() { i++; j++; }
    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }
}

当有两个线程同时不断的分别执行one()和two()方法,会出现有时j的值比i的值大的情况,说明j++有时在i++之前执行。
但当将以上的类修改为下面时:

class Test {
    static int i = 0, j = 0;
    static synchronized void one() { i++; j++; }
    static synchronized void two() {
        System.out.println("i=" + i + " j=" + j);
    }
}

也就是使用synchronized关键字修饰方法one和two后,则不会出现j大于i的情况,也正说明了synchronized具有禁止代码重排序功能

3.验证

以下为完整的不使用synchronized修饰的代码:

package sort;
public class Test1 {
    public static void main(String[] args) {
        MyThread1 thread1 = new MyThread1();
        thread1.start();
        MyThread2 thread2 = new MyThread2();
        thread2.start();
    }
}
class Test {
    static int i = 0, j = 0;
    static void one() { i++;j++; }
    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }
}
class MyThread1 extends Thread {
    @Override
    public void run() {
        while (true) {
            Test.one();
        }
    }
}
class MyThread2 extends Thread{
    @Override
    public void run() {
        while (true) {
            Test.two();
        }
    }
}

截取部分输出为:

···
i=1096461781 j=1096461781
i=1096462439 j=1096462439
i=1096514978 j=1096514985
i=1096515540 j=1096515546
i=1096516081 j=1096516081
i=1096516643 j=1096516642
i=1096517194 j=1096517194
···

可见确实j++有时候在i++之前执行。
接下来,将上面代码中的第12行也就是对one方法加上synchronized关键字,则输出截取部分如下:

···
i=233354804 j=233354804
i=233355026 j=233355026
i=233355534 j=233355534
i=233355776 j=233355776
i=233356003 j=233356003
···

不会出现j++比i++先执行的情况。
注意:可能有的同学在此处想对i和j使用volatile修饰,而不使用synchronized,同样达到禁止重排序的功能,但是事实上这里是错误的,因为可能在执行一次two方法过程中,one方法执行了不止一次,two方法在获得i的值后,one方法又执行了,使得j增加了,这样two方法看到的j可能比i大。
那么为什么使用synchronized不会出现这种情况呢,因为synchronized还有另外一个功能, 就是原子性,i++和j++要么一起执行完,要么都不执行,不会出现先i++后,执行了其他代码,过一会再执行j++的情况。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值