java - 静态成员的多线程行为

标签 java multithreading static java-memory-model

多线程在静态成员的情况下表现如何?就像单例类的情况一样,如果我尝试在静态 block 和静态方法中创建实例,我返回实例并且两个线程尝试同时执行 getInstance() ..这将如何在内部表现为静态只加载一次

public class SingleTonUsingStaticInitialization {

    private static SingleTonUsingStaticInitialization INSTANCE = null;

    static {
        try {
            INSTANCE = new SingleTonUsingStaticInitialization();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private SingleTonUsingStaticInitialization() {
    }

    public static SingleTonUsingStaticInitialization getInstance() {
        return INSTANCE;
    }
}

最佳答案

这个具体的例子?

线程方面没问题。风格明智,这是可悲的。不要那样写 catch block 。这也意味着如果确实发生异常(它不能在这里 - 你的构造函数是空的),你的代码会将一半的信息转储到系统错误,然后继续,使用 Singleton 实例的空引用实例 - 导致其他吐出 NullPointerExceptions 的代码(因为代码一直在运行,因为您捕获了异常而不是让它发生)。如果您以这种方式处理所有异常,一个错误将导致您的日志中出现数百个错误,除了第一个错误外,所有错误都不相关。

一旦解决了这个异常处理问题,就可以使变量final,不再为其赋值null。当你在做的时候,让整个类(class) final。它实际上已经是(因为你只有一个私有(private)构造函数):

public final class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Single() {}

    public static Singleton getInstance() {
        return INSTANCE;
}

当 2 个线程同时调用 getInstance 时,这会起作用的原因是类加载器机制本身:类加载器保证任何给定的类永远不会被同一个加载器加载超过一次,即使 2 个线程将同时需要它(类加载器将同步/锁定以避免这种情况),并且初始化过程(静态 block - 这是不必要的复杂,如上面的示例所示)同样受到保护并且不可能发生两次。

这是您获得的唯一免费赠品:作为一般规则,对于静态方法,所有线程都可以同时运行相同的方法,如果他们愿意的话。在这里他们 - 只是初始化(包括 ... = new Singleton(); 部分)被限制为只发生一次。

注意:如果您必须做更复杂的事情,请制作辅助方法:

public final class Singleton {
    private static Singleton INSTANCE = create();

    private Singleton(Data d) {
        // do stuff with 'd'
    }

    private static Singleton create() {
        Data d;
        try {
            d = readStuffFromDataIncludedInMyJar();
        } catch (IOException e) {
            throw new Error("states.txt is corrupted", e);
        }
        return new Singleton(d);
    }
}

这个:

  1. 保持代码简单 - 静态初始化程序是一回事,但相当奇特的 java。
  2. 使您的代码更易于测试。
  3. 这是一个内部文件;如果它丢失/损坏,那可能/与您的一个类文件去散步一样有问题。这里有一个错误。这不可能发生,除非你写了一个错误或搞砸了一个构建,并且硬崩溃并有一个明确的异常告诉你到底出了什么问题正是你想要在这种情况下发生的事情,而不是让代码盲目地继续处于一半的状态由于磁盘驱动器崩溃或其他原因,您的应用程序被 gobbledygook 覆盖。最好只是总结一切都很无聊,这样说,然后停止运行。

关于java - 静态成员的多线程行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66271829/

相关文章:

java - 如何销毁以前的 Activity

java - 如何终止 View 作用域 bean 中的线程?

java - 如何在多个线程之间安全地共享 ArrayDeque?

c# - ASP.Net 普通类中的静态类

java - 对服务器和远程 JMX bean 使用相同的端口

java - 从变量中获取变量列表

java - 有没有办法将 java 数据类型输出到控制台?

android - 如果用户使用后退按钮,如何处理来自后台线程的反馈?

java - "this"对象与非静态对象

c++ - 如何在头文件库中定义(非方法)函数