我遇到的其中一个 SCJP 练习题提供了 SafeDeposit 类中的代码。该问题的答案声称,如果另一个类使用多个线程,则非同步(非线程安全)getInstance() 方法有可能返回 SafeDeposit 的多个实例。我试了又试,但无法获得 toString() 方法来指示创建了不止一个 SafeDeposit 实例。我是否遗漏了什么,或者这只是“可能”发生但真的、真的、真的不太可能发生的事情之一?
class SafeDeposit {
private static SafeDeposit sd;
public static SafeDeposit getInstance() {
if(sd == null) sd = new SafeDeposit();
return sd;
}
private SafeDeposit() { }
}
public class PrivCon {
public static void main(String[] args) {
String checker;
SafeThief wizard = new SafeThief();
SafeThief wizard2 = new SafeThief();
for(int i = 0; i < 10; i ++) {
new Thread(wizard).start();
new Thread(wizard2).start();
}
}
}
class SafeThief implements Runnable {
public void run() {
System.out.println(SafeDeposit.getInstance().toString());
}
}
最佳答案
is this just one of those things that "could" happen but is really, really, really unlikely to happen?
试试这段代码,看看它到底有多不可能:
class SafeDeposit {
private static SafeDeposit sd;
public static SafeDeposit getInstance() {
if(sd == null) sd = new SafeDeposit();
return sd;
}
private SafeDeposit() { }
static void warmup() {
for (int i = 0; i < 100_000; i++) getInstance();
sd = null;
}
}
public class PrivCon {
public static void main(String[] args) {
SafeDeposit.warmup();
SafeThief wizard = new SafeThief();
for(int i = 0; i < 10; i ++) new Thread(wizard).start();
}
}
class SafeThief implements Runnable {
public void run() {
try { Thread.sleep(100); } catch (InterruptedException e) { }
System.out.println(SafeDeposit.getInstance().toString());
}
}
这是我的典型输出:
test.SafeDeposit@52e5376a
test.SafeDeposit@34780af5
test.SafeDeposit@351775bc
test.SafeDeposit@2b1be57f
test.SafeDeposit@6ae6235d
test.SafeDeposit@6276e1db
test.SafeDeposit@52e5376a
test.SafeDeposit@302b2c81
test.SafeDeposit@60f00e0f
test.SafeDeposit@1732a4df
几乎没有任何重复。
如果您想知道原因,那是因为我添加了预热代码,这导致 getInstance()
方法被 JIT 编译成一段积极优化的代码它利用了 Java 内存模型提供的自由。
我还在 Runnable
的开头添加了一些 sleep
时间,因为一旦一个线程写入值,那些在该点之后启动的线程将可靠地观察到写。所以最好先让所有线程启动,然后让它们调用getInstance
。
关于java - 如何使公共(public)静态非同步 getInstance() 方法将私有(private)静态引用变量的多个实例返回给对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20644203/