Java 帮助检查以下代码,它是线程安全的吗?

Java 帮助检查以下代码,它是线程安全的吗?,java,multithreading,static-methods,Java,Multithreading,Static Methods,构造函数Foo()可能会从多个线程调用。我关心的是私有静态字段“callback”和静态方法“getCallback()” 可以看出,每次调用“getCallback()”时,它都会为静态字段“callback”分配一个新值 我的猜测是,它不是线程安全的,因为关键字static总是附加到类而不是实例,所以这意味着,一个Foo的静态字段“callback”可能会被正在构造另一个Foo()的其他线程覆盖。这是正确的吗 如果我错了,请纠正我。谢谢 编辑:我的意图是在类中的某个地方保留“callback

构造函数Foo()可能会从多个线程调用。我关心的是私有静态字段“callback”和静态方法“getCallback()”

可以看出,每次调用“getCallback()”时,它都会为静态字段“callback”分配一个新值

我的猜测是,它不是线程安全的,因为关键字static总是附加到类而不是实例,所以这意味着,一个Foo的静态字段“callback”可能会被正在构造另一个Foo()的其他线程覆盖。这是正确的吗

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


编辑:我的意图是在类中的某个地方保留“callback”,以便以后可以重用它。但这并不容易,因为Foo是从一个类扩展而来的,该类的构造函数要求传递“回调”。当两个线程同时进入
getCallback()
方法时,
Foo
的两个实例可能以相同的
CallBack
实例结束,其中一个线程向静态字段分配一个新的
CallBack
,而另一个线程已经这样做但尚未返回。在这种情况下,最好的解决方法是不使用静态字段,因为它没有任何用途。或者,使
getCallback()
同步


但请注意,并非只有
static
关键字才会产生非线程安全的代码。

回调将在每次调用Foo()时获得一个新值(即使来自同一线程)。我不太确定您的代码应该做什么(如果您只想初始化静态变量一次(singleton),那么您应该检查getCallback()中的静态变量是否仍然为null-什么是actionCallback?)。要使其线程安全,请使用synchronized。

我认为您自己对其进行了完美的总结,但如果没有更多关于您试图实现的目标的详细信息,则很难提出解决问题的建议


一个明显的问题是,
回调
必须是静态的吗?或者,在不破坏类功能的情况下,可以安全地将其作为实例字段吗?

它不是线程安全的。尝试以下备选方案:

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

private static Callback callback;

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

private static Callback getCallback()
{
    callback = new Callback();
    return callback;
}
选项2:这里每个实例都有自己的回调

private static final Callback callback = new Callback();

public Foo() {
    super(callback);
}

注意,在这两种情况下,尽管构造函数是线程安全的,但整个类的线程安全性取决于回调的实现。如果它具有可变状态,那么您将有潜在的问题。如果回调是不可变的,那么您就有了线程安全性。

我知道它已经被回答了,但是为什么还没有被详细说明

如果有两个线程正在调用getCallback()方法,它们可以执行以下行:

  • 线程1-回调=新回调()
  • 线程2-回调=新回调()
  • 线程1-返回actionCallback
  • 线程2-返回actionCallback 在这种情况下,在(2.)生成的回调将在(3.)和(4)中返回

    解决方案似乎是询问,如果回调特定于实例而不是类,为什么要静态定义它


    我希望这会有所帮助。

    您正在尝试的被称为单例模式,如果您进行搜索,您可以找到为什么如果可以,通常避免这种模式是一个好主意,但是如果您需要它,您可以执行以下操作

    public Foo() {
        super(new Callback());
    }
    
    或者,如果你需要一个懒惰的单身汉,你可以这样做

    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 final static Callback callback;
    
      static {
          callback = new Callback(); 
      }
    
      public Foo()
      {
          super(getCallback());
      }
    
      private static Callback getCallback()
      {
          return callback;
      }
    

    好问题。这些问题很难自己进行逻辑思考,无法编译。actionCallback来自哪里。一般来说,不要通过构造函数初始化静态字段,除非您想引起混淆。对不起,“actionCallback”应该是“callback”。我的意图是在类中的某个地方保留“callback”,以便以后可以重用它。但这并不容易,因为Foo是从一个类扩展而来的,该类的构造函数要求传递“回调”。
      private final static Callback callback;
    
      static {
          callback = new Callback(); 
      }
    
      public Foo()
      {
          super(getCallback());
      }
    
      private static Callback getCallback()
      {
          return callback;
      }
    
      private Callback callback;
    
      public Foo()
      {
          super(getCallback());
      }
    
      private Callback getCallback()
      {
          callback = new Callback();
          return callback;
      }