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

来源:4-1 volatile能够保证可见性

takooya

2019-04-08 08:50

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

写回答 关注

3回答

  • 冰中眼泪
    2020-09-08 17:30:03

    补充一个问题
    之前工作的时候写单例模式,举例如下,主管非得让加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;
        }
    }


    是泪还是累

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

    2022-08-09 20:28:52

    共 1 条回复 >

  • 慕婉清3156049
    2020-05-25 01:41:26

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


  • 爱3
    2020-05-07 15:08:17

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

细说Java多线程之内存可见性

用两种方式实现内存可见性,代领大家深层次学习Java中的内存

55910 学习 · 74 问题

查看课程

相似问题