帮忙看一下下面的代码,线程安全吗?
-
06-09-2019 - |
题
private static Callback callback;
public Foo()
{
super(getCallback());
}
private static Callback getCallback()
{
callback = new Callback();
return callback;
}
构造函数 Foo() 可能会从多个线程调用。我关心的是私有静态字段“callback”和静态方法“getCallback()”。
可以看出,每次调用“getCallback()”时,它都会为静态字段“callback”分配一个新值。
我的 猜测 是它不是线程安全的,因为关键字 静止的 始终附加到类而不是实例,因此这意味着 Foo 的静态字段“callback”可能会被构造另一个 Foo() 的其他线程覆盖。它是否正确?
如果我错了,请纠正我。谢谢!
编辑:我的目的是将“回调”保留在类中的某个位置,以便以后可以重用它。但这并不容易,因为 Foo 继承自一个类,该类具有强制传递“回调”的构造函数。
解决方案
是的,你是正确的。这是可能的Foo
的两个实例使用相同CallBack
情况下结束,当两个线程同时进入getCallback()
方法之一,而另一个已经做到了这一点,但没有返回一个新的CallBack
分配给静态字段。在这种情况下,最好的解决方法是不具有静态字段,因为它没有任何意义。可替换地,使getCallback()
同步。
但是请注意,这是的不的事实,只有在代码中static
的关键字结果不是线程安全的。
其他提示
这不是线程安全的。尝试这些替代选择:
选项1:这里所有实例共享相同的回调
private static final Callback callback = new Callback();
public Foo() {
super(callback);
}
选项2:每个这里实例都有自己的回调
public Foo() {
super(new Callback());
}
请注意,在这两种情况下,虽然构造函数是线程安全的,整个班级的线程安全取决于回调的实现。如果它有可变的状态,那么你就会有潜在的问题。如果回调是不可改变的,那么你有线程安全的。
回调将获得新的值每一次的Foo()被调用(甚至在同一个线程)。我不太清楚你的代码应该做的(如果你想只有一次(单身初始化静态变量),你应该检查,如果它仍然是空的getCallback() - 什么是actionCallback?)。用于使得线程安全的,使用同步。
我想你总结的那样完美自己,但没有更详细的关于你正在努力实现这将是棘手的提出建议,以解决您的问题是什么。
一个明显的问题是,不callback
已经是静态的?或者,你能安全地使一个实例字段而不破坏你的类的功能?
我知道这个问题已经得到解答,但原因还没有详细说明。
如果两个线程调用 getCallback() 方法,它们可以执行如下几行:
- 线程 1 - 回调 = new Callback();
- 线程 2 - 回调 = new Callback();
- 线程1——返回actionCallback;
- 线程2——返回actionCallback;
在这种情况下,在 (2.) 处生成的回调将在 (3.) 和 (4.) 中返回
解决方案似乎是问为什么回调是静态定义的,如果它特定于实例而不是类。
我希望这有帮助。
你所试图做的是称为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());
}
两种实现都是线程安全。
你想每一个线程回调,每一个对象,或者一个真正的单身?
这是怎么做的不同的变体的一些草图 - 只是从我的头顶,不采取这些文生义:)
请注意,我假设回调有一个平凡的构造函数可能抛出异常,需要进行处理,如果它是一个平凡的构造可以简化所有这些很多。
一每线程:
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;
}