单例调用的构造函数中的同步块是否会同步 Java 中的线程?

Will synchronized block in constructor of singleton calls synchronise the threads in Java?

我正在尝试一些疯狂的事情 :p

创建了一个 TestClass(遵循单例设计模式) 初始化 TestClass 的反射并启动两个使用反射创建 TestClass 新实例的线程的主要方法。

下面是代码

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class SingletonPattern {
    public static void main(String[] args) throws InterruptedException, IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        final TestClass[] i1 = {null};
        final TestClass[] i2 = {null};

        final Constructor<TestClass> constructor = TestClass.class.getDeclaredConstructor();
        constructor.setAccessible(true);

        Thread t3 = new Thread() {
            @Override
            public void run() {
                try {
                    i1[0] = constructor.newInstance();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        Thread t4 = new Thread() {
            @Override
            public void run() {
                try {
                    i2[0] = constructor.newInstance();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        t3.start();
        t4.start();
        t3.join();
        t4.join();
        System.out.println((i1[0] == i2[0]) + "  " + i2[0].equals(i1[0]));
    }


    static class TestClass implements Cloneable, Serializable{
        private static TestClass instance;
        private static final Object obj = new Object();

        private TestClass() {
            synchronized (TestClass.class) {
                for (int i = 0; i < 100000; i++) ;
                if (instance != null) {
                    throw new RuntimeException("Operation not allowed. Use getInstance method.");
                }
            }
        }

        public static TestClass getInstance() {
            if (instance == null) {
                synchronized (TestClass.class) {
                    if (instance == null) {
                        for (int i = 0; i < 100000; i++) ;
                        instance = new TestClass();
                    }
                }
            }
            return instance;
        }

        public static TestClass getClone() {
            try {
                return (TestClass) instance.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected Object clone() throws CloneNotSupportedException {
            return instance;
        }

        private Object readResolve() {
            return getInstance();
        }
    }
}

我得到的输出

false false

如果构造函数中的同步块真的同步了,那么我应该会看到一些异常。但这并没有发生。

谁能解释一下为什么会这样? 我正在使用 Java 版本:corretto-1.8.0_282

If the synchronized block in constructor are really getting synchronised then I should be seeing some exception. But that is not happening.

在您的 constructor 方法中,instance != null 将始终 return false 因为 instace 从未被赋值。

可以加上instance = this,这样的话,只有一个线程可以通过反射构造实例,其他线程会得到异常:

       private TestClass() {
            synchronized (TestClass.class) {
                for (int i = 0; i < 100000; i++) ;
                if (instance != null) {
                    throw new RuntimeException("Operation not allowed. Use getInstance method.");
                }
                instance = this;
            }
        }