为了账号安全,请及时绑定邮箱和手机立即绑定

synchronized是否限制内部代码的重排序

synchronized所修饰的内部代码是否会重排序

正在回答

5 回答

补充一个问题
之前工作的时候写单例模式,举例如下,主管非得让加volatile来修饰single,说如果不加会有重排序问题,从而导致空指针,但是看到大家的讨论和老师的回答,我觉得不需要加volatile,因为synchronized关键字已经保证了只会有一个线程进入创建单例对象的代码,当这个线程锁释放的时候,因为happens-before原则,其他线程拿到的单例一定是完整的,也就是说这个单例的属性一定是已经被赋值的,不会出现空指针问题,请问老师我的理解准确吗

public class ExampleSingle {

    private volatile static ExampleSingle single;
        ***一些属性
    private ExampleSingle() {
            *** 假如这里对这些属性进行了赋值操作
    }

    public static ExampleSingle getInstance() {
        if (single == null) {
            synchronized (ExampleSingle.class) {
                if (single == null) {
                    single = new ExampleSingle();
                }
            }
        }
        return single;
    }
}


0 回复 有任何疑惑可以回复我~
#1

是泪还是累

single = new ExampleSingle(); 大体分为三步 1.分配内存 2.初始化 3.将引用指向内存地址 你这个方法 ExampleSingle并没有加sychronized,所以是不阻塞,可以进来,可sychronized并不保证指令重排序,所以3.将引用指向内存地址 重排序到2.初始化前,那么就这时single != null 而直接返回,退出方法,人家还没有执行第二步初始化,所以拿到了一个未初始化后的single,进行操作就会出现问题,所以需要引入volatile进行禁止重排序,禁止了2和3的操作重排序。
2022-08-09 回复 有任何疑惑可以回复我~

不会限制,被synchronized修饰的代码会被编译器或者处理器重排序。多个线程如果不加同步锁,重排序可能会导致可见性问题(线程A中代码顺序不一致可能导致线程B得到错误的结果,即使线程A符合as-if-serial语义),而如果加了同步锁,不会导致可见性问题,因为线程A的所有操作对于线程B来说都是可见的。synchronized的作用主要是两点:1.保证有序性:使多个线程之间有序执行,不会出现交叉执行。2.保证可见性:线程解锁前,必须把共享变量的最新值刷新到主内存中,线程加锁时,需要从主内存中重新读取最新值。


0 回复 有任何疑惑可以回复我~

不会,它的作用是在多线程情况下的。单线程下重排序是不会影响执行结果的。

0 回复 有任何疑惑可以回复我~

举报

0/150
提交
取消

synchronized是否限制内部代码的重排序

我要回答 关注问题
意见反馈 帮助中心 APP下载
官方微信