单例调用的构造函数中的同步块是否会同步 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;
}
}
我正在尝试一些疯狂的事情 :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;
}
}