public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
if (instance == null) //2
instance = new Singleton(); //3
}
}
return instance; //4
}
在上面的代码中,假设有10个线程正在调用此方法,所有这些线程都超过了第一个if条件,然后一个线程进入synchronized块并创建实例。即使创建了实例,他们也需要经过同步块,剩下的9个线程应该逐个到来。只要任何线程创建了Singleton实例,所有其他线程就不应该等待。告诉我是否有解决方案吗?
答案 0 :(得分:0)
我认为它的良好代码和阻塞时间不会那么多,因为Singleton不是非常复杂的结构化类,或者在构造函数的初始化中没有太多东西需要加载。如果所有线程同时出现,则必须等到任何一个线程创建第一个对象。
答案 1 :(得分:0)
没有条件同步。这意味着无论何时使用synchronized,都会在整个时间内强制执行。 在上面的例子中,它当然是一个在静态块中初始化Singleton的选项,然后你不需要getter的synchronized块。
答案 2 :(得分:0)
你是说你希望所有其他九个线程都能在不获取锁定的情况下运行。
首先,我觉得有必要提一下,等待初始化后获取锁的性能问题很小。其次,单身人士是邪恶的,有更好的方法来实施它们。
但是,如果要部分重新实现锁定,则可以执行此操作。可能有一些现成的Future
这样做,但我看不到任何东西。无论如何,糟糕的实施是我的头脑:
private static final AtomicReference<Object> ref = new AtomicReference<>();
// <Object> as we require two distinguished values. :(
// (I guess could use a mark.)
public static Singleton getInstance() {
for (;;) { // May want to play with park to avoid spinning.
Object obj = ref.get();
if (obj instanceof Singleton) {
return (Singleton)obj;
}
if (ref.weakCompareAndSet(null, Thread.currentThread())) {
Singleton instance = null; // To reset on fail.
try {
instance = new Singleton();
} finally {
ref.set(instance);
}
return instance;
}
}
}
我想我们可以做得稍好一点而不会太复杂,再次假设没有例外:
{
Object obj = ref.get();
if (obj instanceof Singleton) {
return (Singleton)obj;
}
}
if (ref.compareAndSet(null, Thread.currentThread())) {
Singleton instance = new Singleton();
ref.set(instance);
return instance;
}
for (;;) {
Object obj = ref.get();
if (obj instanceof Singleton) {
return (Singleton)obj;
}
}
答案 3 :(得分:0)
正如你的设计一样,剩下的线程确实必须一次经过一个线程 - 而且对于任何这样的锁定策略你都会得到相同的结果。也就是说,现在锁定的成本微不足道。
请注意,虽然未显示,但instance
变量必须为volatile
才能使此习语成效。
如果你想要一个能够完成你所追求的模式(以低成本进行延迟初始化),那么我建议使用静态初始化方法(根据Brian Goetz的建议):
public class Singleton {
static class Holder {
static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
这种方法很简洁,并且也是线程安全的,在你的情况下,第一个访问静态getInstance
方法(或任何静态方法)的线程将支付初始化的成本,但所有后续的不会,也不会阻止。