Java单例模式在多线程中输出两个相同的对象?

标签 java singleton

public class Foo {

    private static  Foo foo;
    private Foo(){}
    public static Foo getInstance(){
        if (foo==null){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {}
            foo = new Foo();
            System.out.println(foo+"----"+Thread.currentThread().getName());
        }
        return foo;
    }

    public static void main(String[] args) throws Exception {

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() { 
                Foo foo1 = Foo.getInstance();
            }
        },"thread1");

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Foo foo2 = Foo.getInstance();
            }
        },"thread2");
    thread1.start();
    thread2.start();
    }
}

我只想模拟这些代码在多线程环境中是不安全的,但它总是输出两个相同的对象,如:

Foo@24c21495----thread1
Foo@24c21495----thread2

Foo@3d4b7453----thread1
Foo@3d4b7453----thread2

...

为什么?

最佳答案

我认为这里有两个综合原因:

  • 打印的第一件事就是结果。各种代码可能正在此处进行 JIT 编译,并可能初始化其他资源。我相信这是一个有效的固有同步点。
  • 你的 sleep 时间很短,而且很均匀,这无济于事。

基本上,我相信两个线程都在创建新实例,然后都在显示结果 - 除非你“幸运”,否则两个线程都会看到第二个执行分配的线程的结果。

如果你只是添加:

System.out.println("Starting");

main 的最开始,您有时会看到不同的输出。如果你也改变你的 sleep :

Thread.sleep((long) (Math.random() * 100));

...那么您就更有可能看到它。基本上,您希望一个线程在另一个线程处于 sleep 状态时完成整个“ sleep 、初始化、打印”。

另一种选择是简单地向构造函数添加打印语句:即使两个线程在您当前的诊断位置显示相同的对象,您仍然会看到正在构造两个实例,这表明代码是不安全的。

关于Java单例模式在多线程中输出两个相同的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16890773/

相关文章:

java - 从 java 集合中删除重复项

java - Eclipse:显示方法列表(ctrl-space)时,有没有办法在该类中添加方法 - 粗体?

c# - 为采用参数/参数的类创建单例工厂

android - 在 Android/Java 中将全局对象实现为单例或 DataClass 的优缺点

objective-c - 使用 allocWithZone : 创建单例

java - 使用 Spring WS Test 测试 CXF 客户端

java - 如果 TRY 错误

java - 尝试在 Java 的循环中使用 Switch 语句

c# - 单例模式——创建对象

java - 单例模式对象实例化时间