JAVA应用】单例模式的线程安全性

2020-11-18 19:10发布

5条回答
天天
2楼 · 2020-11-19 09:34

单例模式是为确保一个类只有一个实例,并为整个系统提供一个全局访问点的一种模式方法。

单例模式的特点:

(1)、在任何情况下,单例类永远只有一个实例存在。

(2)、单例需要有能力为整个系统提供这一唯一实例。


小猪仔
3楼 · 2020-11-19 09:37

单例模式的作用就是保证类只有一个实例对象。
分为懒汉式和饿汉式,听名字就能知道个大概了,直接贴代码。

懒汉式:

/**
 * 懒汉代理模式
 */public class Singleton {

    //私有构造方法
    private Singleton() {

    }

    // 单例对象
    private static Singleton singleton = null;

    public Singleton getSingleton() {
        if (null == singleton) {
            singleton = new Singleton();
        }
        return singleton;
    }}1234567891011121314151617181920

线程安全问题: 如果有两个线程,同一时刻拿到单例对象,要去静态工厂办法访问,由于工厂办法没有锁,那么很有可能这两个线程最终会拿到两个实例。

饿汉式:

/**
 * 饿汉式代理模式
 */public class Singleton2 {

    // 私有构造函数
    private Singleton2() {

    }

    // 单例对象
    private static Singleton2 singleton2 = new Singleton2();

    // 静态的工厂方法
    public static Singleton2 getInstance() {
        return singleton2;
    }}123456789101112131415161718

饿汉式和懒汉式相比,是线程安全的,缺点是比较耗费内存,应用一加载就会直接放到堆中。

线程安全的饿汉式:

public class Singleton3 {

    // 私有构造函数
    private Singleton3() {

    }

    // 单例对象 volatile + 双重检测机制 -> 禁止指令重排
    private volatile static Singleton3 singleton3 = null;

    // 静态的工厂方法
    public static Singleton3 getInstance() {
        if (singleton3 == null) { // 第一层检查,检查是否有引用指向对象,高并发情况下会有多个线程同时进入
            synchronized (Singleton3.class) { // 第一层锁,保证只有一个线程进入
             //双重检查,防止多个线程同时进入第一层检查(因单例模式只允许存在一个对象,故在创建对象之前无引用指向对象,所有线程均可进入第一层检查)
                //当某一线程获得锁创建一个Singleton对象时,即已有引用指向对象,singleton不为空,从而保证只会创建一个对象
                //假设没有第二层检查,那么第一个线程创建完对象释放锁后,后面进入对象也会创建对象,会产生多个对象
                if (singleton3 == null) {
                //volatile关键字作用为禁止指令重排,保证返回Singleton对象一定在创建对象后
                    singleton3 = new Singleton3(); // A - 3
                }
            }
        }
        return singleton3;
    }}


魏魏姐
4楼 · 2020-11-19 10:37

 单例也不能保证100%线程安全的。解决方法就是创建实例方法中加入Java关键字synchronized。 

是你的小甜心呀
5楼 · 2020-11-19 17:17

概念:
  java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
  单例模式有一下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。
  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

不爱编程的刘老师
6楼 · 2020-11-20 17:02

老生常谈的问题了,首先要说的是的线程安全意味着:某个类的实例在多线程环境下只会被创建一次出来。有很多种的写法,我总结一下:


(1)饿汉式的写法:线程安全


(2)懒汉式的写法:非线程安全


(3)双检锁的写法:线程安全

相关问题推荐

  • 回答 20

    100-199 用于指定客户端应相应的某些动作。 200-299 用于表示请求成功。 300-399 用于已经移动的文件并且常被包含在定位头信息中指定新的地址信息。 400-499 用于指出客户端的错误。 400 语义有误,当前请求无法被服务器理解。 401 当前请求需要用户验证...

  • 回答 5
    已采纳

    1、相同点(1)都是表现层框架,都是基于MVC设计模型(2)底层都离不开 Servlet API(3)处理请求的机制都是一个核心控制器2、不同点(1)SpringMVC的入口是Servlet,而Struts2的入口是Filter(2)SpringMVC是基于方法设计的,而Struts2是基于类(3)SpringMV...

  • 回答 22
    已采纳

    类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结...

  • 回答 23
    已采纳

    (1)idea启动时会有两个快捷方式,安装完后默认生成在桌面的是32位的idea的快捷方式,如果我们使用这个快捷方式运行大项目,一般都会很卡。解决方法是找到idea的安装目录,然后进入bin文件夹,找到名称为idea64的应用程序,右键他生成桌面快捷方式。以后每次...

  • 回答 12
    已采纳

    获取Map集合中所有的key可以通过map集合的keySet()方法获取例如:    Map map = new HashMap();    map.put(xx,xx); //存放数据    //.... 省略    Set set = map.keySet();    //可以通过迭代器进行测试    Iterator iter = set.iter...

  • 回答 4
    已采纳

    Java中有八种数据类型,基础数据类型分别是:byte,short,int,long,float,double,char,boolean,引用数据类型分别是:数组,类和接口。方法传参的时候我们有两种,一种是形式参数(定义方法时写的参数),一种是实际参数(调用方法时给的具体值)。首先...

  • 回答 15
    已采纳

    现在的架构很多,各种各样的,如高并发架构、异地多活架构、容器化架构、微服务架构、高可用架构、弹性化架构等,还有和这些架构相关的管理型的技术方法,如 DevOps、应用监控、自动化运维、SOA 服务治理、去 IOE 等等,还有很多。分布式架构其实就是分布式系...

  • 回答 10

    1、监控GC的状态使用各种JVM工具,查看当前日志,分析JVM参数的设置,分析堆内存快照和GC日志,根据实际的各区域的内存划分和GC的执行时间,判断是否需要进行优化2、分析结果、判断是否需要优化如果各项参数设置合理,系统没有超时的日志出现,GC频率也不高,...

  • 回答 7

    没有所谓的核心线程,线程只有单线程和多线程之分~首先,关于计算机系统的很多概念,都有逻辑层 和 物理层的区分,这个是前提。然后再看,核心这个概念是物理层的概念,指的就是 CPU硬件的物理核心数量。而线程 这个概念,是逻辑层的概念,而且这个逻辑层的概...

  • 回答 2

    groupNum = / List listThreads = ArrayList()(i = i 

  • 回答 4

    多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程...

  • 回答 18

    这是一个非常刁钻和狡猾的问题。请记住:线程类的构造方法、静态块是被 new这个线程类所在的线程所调用的,而 run 方法里面的代码才是被线程自身所调用 的。如果说上面的说法让你感到困惑,那么我举个例子,假设 Thread2 中 new 了 Thread1,main ...

  • 回答 26

    多线程类似于同时执行多个不同程序,多线程运行有如下优点:使用线程可以把占据长时间的程序中的任务放到后台去处理。用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度程序的运行速度可能加快在...

  • 回答 7

    同步块是更好的选择,因为它不会锁住整个对象(当然你也可以让它锁住整个对象)。同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁。...

  • 回答 5
    已采纳

    很多人都知道死锁是怎么一回事儿:线程A和线程B相互等待对方持有的锁导致程序无限死循环下去。当然也仅限于此了,问一下怎么写一个死锁的程序就不知道了,这种情况说白了就是不懂什么是死锁,懂一个理论就完事儿了,实践中碰到死锁的问题基本上是看不出来的。...

没有解决我的问题,去提问