java - 测试线程安全单例的代码中的奇怪行为

标签 java multithreading enums singleton

我对 Java 中的多线程相当陌生。因为我需要一个线程安全的单例(我将其实现为枚举),所以我编写了一个小的测试代码,它产生了一个奇怪的输出。

代码:

public enum EnumSingleton {
    INSTANCE;


    /** state variables */
    private String message;

    /** Constructor */
    private EnumSingleton() {
    }

    /** add well-known accessor for the instance  (is NOT necessary) */
    public static EnumSingleton getInstance() {
        return INSTANCE;
    }


    /** Accessors */
    public String getMessage() {
        return message;
    }

    public void setMessage(String name) {
        this.message = name;
    }
}

public class App {

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {
            final int b = i;
            Thread thread = new Thread("Thread #" + b) {
                @Override
                public void run() {
                    EnumSingleton singleton = EnumSingleton.getInstance();
                    singleton.setMessage("Message written by "+this.getName());
                    System.out.println("Current thread "+this.getName() + ": "+singleton.getMessage());
                }
            };
            thread.start();
        }
    }
}

因此每个线程都将其名称写入枚举的属性“message”中,然后将其打印到 STDOUT。我得到以下我觉得很奇怪的输出:

Current thread Thread #6: Message written by Thread #3
Current thread Thread #1: Message written by Thread #1
Current thread Thread #8: Message written by Thread #8
Current thread Thread #5: Message written by Thread #1
Current thread Thread #4: Message written by Thread #4
Current thread Thread #9: Message written by Thread #9
Current thread Thread #7: Message written by Thread #3
Current thread Thread #2: Message written by Thread #3
Current thread Thread #0: Message written by Thread #3
Current thread Thread #3: Message written by Thread #3

我期望的是我为每个循环计数器 (0-9) 得到一条消息。但是在这个例子中,我有多个线程 #3 写的消息,怎么可能呢?是否存在竞争条件?

如果我的代码很糟糕:如何正确测试单例的线程安全性?

最佳答案

这里有一个明显的竞争条件,因为枚举的单例实例中有一个变量 message。您的线程都在同时写入和读取该变量,因此您会期望看到这样的结果。

枚举构造意味着您的单例对象的创建是线程安全的,但是仍然需要正确处理对其中方法的调用。

做你正在寻找的方法是让 message 成为 thread local变量或将消息的设置和消息的读取放在单个 synchronized block 中,可能锁定在单例对象上。

关于java - 测试线程安全单例的代码中的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34068864/

相关文章:

java - 什么是 ScalaSignature?

Java应用程序制作显卡0x1​​04567910

具有多个值的Java枚举valueOf()?

c# - 将匿名方法传递给 ProgressBar.Invoke()

java - 在 Java 中分配枚举值

C++ 枚举与 unsigned int 比较

JAVA获取文件修改时间并删除

java - 如何使用 Gmail API 检索电子邮件正文内容?

vb.net - 为什么 Thread.Abort 仅在 isBackground 属性设置为 true 时才有效?

Python监控子进程的stderr和stdout