2009-06-01 60 views
3
private static Callback callback; 

public Foo() 
{ 
    super(getCallback()); 
} 

private static Callback getCallback() 
{ 
    callback = new Callback(); 
    return callback; 
} 

构造函数Foo()可能会被多个线程调用。我关心的是私有静态字段'callback'和静态方法'getCallback()'。帮忙查看下面的代码,线程安全吗?

如可以看到的,每一次“getCallback()”被调用时,它分配一个新的值,以静态字段“回调”。

猜测是,它不是线程安全的,因为关键字静态始终附加到类而不是实例,这样就意味着,一个Foo的静态字段“回调”有可能被其他覆盖正在构造另一个Foo()的线程。它是否正确?

如果我错了,请纠正我。谢谢!

编辑:我的意图是保持'回调'在类的某个地方,所以我可以在以后重复使用。但是这并不容易,因为Foo从一个具有构造函数的类中继承,该类需要传递'callback'。

+1

好问题。这些问题很难通过自己逻辑思考。 – 2009-06-01 09:53:21

回答

6

是的,你是对的。这是可能的Foo两个实例具有相同CallBack情况下结束,当两个线程同时进入getCallback()方法之一,而另一个已经做到了这一点,但没有返回分配一个新的CallBack到静态字段。在这种情况下,最好的解决办法是不要有静态字段,因为它没有任何用处。或者,使getCallback()同步。

但请注意,它是而不是确实只有static关键字会导致非线程安全的代码。

3

每次调用都会得到一个新的值Foo()被调用(即使从同一个线程)。我不太清楚你的代码应该做什么(如果你只想初始化静态变量一次(singleton),你应该检查getCallback()是否仍然为null)以及什么是actionCallback?)。为了使其线程安全,请使用synchronized。

2

我认为你自己总结得很完美,但没有更多关于你想要实现的细节,提出解决问题的建议将会非常棘手。

一个明显的问题是,是否callback必须是静态的?或者你可以安全地将它作为一个实例字段而不会破坏你的类的功能?

5

它不是线程安全的。尝试这些替代选择:

选项1:这里的所有实例共享相同的回调

private static final Callback callback = new Callback(); 

public Foo() { 
    super(callback); 
} 

选项2:这里的每个实例都有自己的回调

public Foo() { 
    super(new Callback()); 
} 

注意,在这两种情况下,虽然构造函数是线程安全的,整个类的线程安全性取决于Callback的实现。如果它有可变状态,那么你将会有潜在的问题。如果回调是不可变的,那么你有线程安全。

2

我知道它已被回答,但为什么没有真正详细。

它两个线程调用getCallback()方法,如下所示它们可以执行行:

  1. 线程1 - 回调=新回调();
  2. 线程2 - 回调=新回调();
  3. 线程1 - 返回actionCallback;
  4. 线程2 - 返回actionCallback;

在这种情况下,在(2)中产生的回调将在两个(3)返回,并(4)

溶液似乎是问为什么回调staticly如果它定义特定于不是类的实例。

我希望有帮助。

1

你所试图做的是称为Singleton模式,如果你做一个搜索,你可以找出为什么它通常是一个好主意,如果你能避免这个模式,但是如果你需要它,你可以做到以下几点。

private static final Callback CALLBACK= new Callback(); 

,或者您需要一个懒惰的单身,你可以做

public class Foo { 
    class CallbackHolder { 
     static final Callback CALLBACK= new Callback(); 
    } 

    public static Callback getCallback() { 
     return CallbackHolder.CALLBACK; 
    } 

public Foo() { 
    super(getCallback()); 
} 

两者的实现是线程安全的。

1

你想每一个线程回调,每一个对象,或者一个真正的单身?

如何做不同的变体的一些草图 - 只是从我的头顶,不采取这些文生义:)

请注意,我假设回调有一个平凡的构造函数可能会抛出需要处理的异常,如果它是一个简单的构造函数,则可以简化所有这些。

每一个线程:

private static ThreadLocal<Callback> callback; 

    public Foo() 
    { 
     super(getCallback()); 
    } 

    private static Callback getCallback() 
    { 
     if (callback.get() == null) 
      callback.set(new Callback()); 
     return callback.get(); 
    } 

单回调所有线程:

private final static Callback callback; 

    static { 
     callback = new Callback(); 
    } 

    public Foo() 
    { 
     super(getCallback()); 
    } 

    private static Callback getCallback() 
    { 
     return callback; 
    } 

而且,对于completness,每个对象一个回调:

private Callback callback; 

    public Foo() 
    { 
     super(getCallback()); 
    } 

    private Callback getCallback() 
    { 
     callback = new Callback(); 
     return callback; 
    }