当前位置: 首页 > 知识库问答 >
问题:

多线程环境中的单例模式

马天逸
2023-03-14
class Single {

        private final static Single sing = new Single();       
        private Single() {
        }        
        public static Single getInstance() {
            return sing;
        }
    }

现在,他提出的下一个问题是为多线程环境编写单例类。然后,我写了双重检查单例类。

  class MultithreadedSingle {        
        private static MultithreadedSingle single;       
        private MultithreadedSingle() {
        }        
        public static MultithreadedSingle getInstance() {
            if(single==null){
                    synchronized(MultithreadedSingle.class){
                      if(single==null){
                            single= new MultithreadedSingle(); 
                              }      
                      }
                   }
             return single;
        }
    }

然后,他反对使用synchronized和双重检查,并说这是没用的。为什么要检查两次,为什么要使用synchronized?我试着用多种方案说服他。但是,他没有。

后来,我在家里尝试了下面的代码,在那里我使用了带有多个线程的简单的单例类。

public class Test {

    public static void main(String ar[]) {
        Test1 t = new Test1();
        Test1 t2 = new Test1();
        Test1 t3 = new Test1();
        Thread tt = new Thread(t);
        Thread tt2 = new Thread(t2);
        Thread tt3 = new Thread(t3);
        Thread tt4 = new Thread(t);
        Thread tt5 = new Thread(t);
        tt.start();
        tt2.start();
        tt3.start();
        tt4.start();
        tt5.start();

    }
}

final class Test1 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " : " + Single.getInstance().hashCode());
        }
    }

}
     class Single {

        private final static Single sing = new Single();       
        private Single() {
        }        
        public static Single getInstance() {
            return sing;
        }
    }
Thread-0 : 1153093538
Thread-0 : 1153093538
Thread-0 : 1153093538
Thread-0 : 1153093538
Thread-0 : 1153093538
Thread-4 : 1153093538
Thread-1 : 1153093538
Thread-2 : 1153093538
Thread-3 : 1153093538
Thread-3 : 1153093538
Thread-3 : 1153093538
Thread-3 : 1153093538
Thread-3 : 1153093538
Thread-2 : 1153093538
Thread-2 : 1153093538
Thread-2 : 1153093538
Thread-2 : 1153093538
Thread-1 : 1153093538
Thread-1 : 1153093538
Thread-1 : 1153093538
Thread-1 : 1153093538
Thread-4 : 1153093538
Thread-4 : 1153093538
Thread-4 : 1153093538
Thread-4 : 1153093538

那么,问题是,在多线程环境中是否有必要使用synchronize或/和双重检查方法?似乎我的第一个代码本身(没有添加任何额外的代码行)就是这两个问题的答案。任何更正和知识分享将不胜感激。

共有1个答案

齐乐逸
2023-03-14

你的第一个例子是绝对正确的,通常是单身人士首选的“习语”。另一种是制作单元素枚举:

public enum Single {
    INSTANCE;

    ...
}

这两种方法非常相似,除非类是可序列化的,在这种情况下,枚举方法更容易得到正确的处理--但是如果类不是可序列化的,我实际上更喜欢枚举方法,因为这是一个风格问题。小心由于实现一个接口或扩展一个本身可序列化的类而“意外地”变成可序列化。

在双重检查锁示例中,第二次检查无效也是正确的。但是,sing字段必须是volatile,这样才能在Java中工作;否则,在一个线程写入sing和另一个线程读取它之间就没有正式的“发生前”边缘。这可能导致第二个线程看到null,即使第一个线程分配给变量,或者,如果sing实例有状态,它甚至可能导致第二个线程只看到该状态的一部分(看到部分构造的对象)。

 类似资料:
  • 我的 Web 应用程序中出现随机错误,我迷路了。我创建了一个库来解码代码。我尝试了很多,从未失败过测试。但突然间,它开始随机失败。由于它在单线程测试中运行良好,有时在 servlet 环境中失败时,我能想象的唯一解释是问题与多线程环境中使用的库有关。老实说,我知道多线程是一个非常复杂的问题。我担心我的库可能不是线程安全的。顺便说一下,它非常简单,它是一个具有几种静态方法的正面类。基本上,假设您正在

  • 我在学习多线程时发现对象的速度变慢了。hashCode在多线程环境中,因为对于相同数量的对象,计算运行4个线程的默认哈希代码要比运行1个线程的默认哈希代码花费两倍的时间。 但根据我的理解,并行完成这项工作也需要类似的时间。 您可以更改线程数。每个线程都有相同的工作量,因此您希望在我的四核机器上运行4个线程可能需要与运行单个线程相同的时间。 我看到4x大约2.3秒,但是。1x为9秒。 我的理解是否有

  • 如果我有多个线程,每个线程使用injector获取EntityManager对象,每个线程使用em对象选择其他类对象的列表。准备好在for循环中使用。 如果一个线程首先完成并调用clear(),这会影响其他线程吗?比如for循环会有异常? 谢谢你。

  • 本文向大家介绍Java多线程实战之单例模式与多线程的实例详解,包括了Java多线程实战之单例模式与多线程的实例详解的使用技巧和注意事项,需要的朋友参考一下 1、立即加载/饿汉模式 立即加载/饿汉模式是在类创建的同时已经创建好一个静态的对象供系统使用,不存在线程安全问题 2、延迟加载/懒汉模式 延迟加载/懒汉模式是在调用方法时实例才被创建,在多线程环境下,会出现取出多个实例的情况,与单例模式的初衷是

  • 问题内容: 在多线程环境中使用Singleton类的首选方法是什么? 假设我有3个线程,并且所有这些线程都尝试同时访问单例类的方法- 如果不保持同步会怎样? 在内部使用 方法还是使用块是好的做法。 请告知是否还有其他出路。 问题答案: 从理论上讲,这项任务并不容易,因为您要使其真正成为线程安全的。 在此上找到了一篇非常不错的论文@ IBM 仅获取单例不需要任何同步,因为这只是读取。因此,只需同步S

  • 问题内容: 将Singleton对象重构到集群环境的最佳策略是什么? 我们使用Singleton从数据库中缓存一些自定义信息。它 主要是 只读的,但是在发生某些特定事件时会刷新。 现在,我们的应用程序需要部署在集群环境中。根据定义,每个JVM将具有自己的Singleton实例。因此,当在单个节点上发生刷新事件并且刷新其缓存时,JVM之间的缓存可能不同步。 保持缓存同步的最佳方法是什么? 谢谢。 编