先看看什么是单例设计模式呢?
单例设计模式,也称单态(原子)设计模式。最初起始于建筑行业,建筑行业把建筑中中的一些常见问题进行了归纳总结,并给出了具体的解决方案。(简单理解就是解决问题的模板)
单例设计模式 ,是用来解决:程序中的所创建出来的对象只有一个(创建的对象在堆内存中只开辟一个空间)。
问题1:只要使用new关键字,就可以创建不同的对象(如何保证只能有一个对象呢?)反向思考:不让其它程序去创建对象,就不会有不同对象存在于堆空间下
问题2:不让使用new创建对象了,那么唯一的一个对象怎么创建呢?可以在本类中创建一个属于本类自己的对象
问题3:在本类创建属于自己的对象,那么其它程序怎么去访问这个唯一对象? 可以对外提供一个public方法,把创建出来的唯一对象返回出去,供其它程序使用
根据分析的问题,怎么去实现呢?考虑一下问题
问题1:不让其它程序去使用new创建对象? 方法:把构造函数私有化
问题2:其它程序无法创建对象了,唯一的对象怎么出现?方法:在本类中创建一个属于本类自己的对象(自已创建自己的对象)
问题3:其它程序怎么去访问这个创建出来的唯一对象?方法:在本类中提供一个public方法,把创建出来的唯一对象,返回出去
基于以上三点,使用代码体现:
package com.Thread.demo; //单例设计模式,懒汉式 class Single{ //第一步:私有化构造函数 private Single(){} //第二步:创建本类对象,初始化为null private static Single instance =null; //第三步:对外一个公共方法 public static Single getInstance(){ //判断对象是否为空,就创建对象 if (instance==null) { instance=new Single(); } //把唯一的对象返回出去 return instance; } } public class SingleDemo1 { public static void main(String[] args) { //获取单例对象 Single s1 = Single.getInstance(); } }当针对单例的懒汉式添加多线程后,该对象就不唯一了如:
package com.Thread.demo; import sun.security.jca.GetInstance; /** * 单例懒汉式的多线程操作的安全问题 * */ class Single{ //第一步:私有化构造函数 private Single(){ } //第二步:创建本类自己对象,初始化为空 public static Single instance =null; //对外提供一个公共方法,返回唯一对象 public static Single getInstance(){ //判断,为空时创建本类对象 if (instance==null) { instance =new Single(); } //返回唯一的对象 return instance; } } //创建线程任务类,测试多线程操作单例的懒汉式的安全问题 class Task implements Runnable{ //复写run方法,书写线程任务 public void run() { //获取单例对象,,输出其地址 System.err.println(Single.getInstance()); } } public class SingleThreadDemo { public static void main(String[] args) { //创建任务对象 Task task= new Task(); //创建线程对象,将任务对象作为参数传递 Thread t1= new Thread(task); Thread t2= new Thread(task); //开启线程 t1.start(); t2.start(); } }运行结果:
可以看出当开启两个线程去执行单例任务的时候,获取的两个对象地址不唯一!那么怎么解决呢?
方法很简单:就是对多线程共同操作的代码块添加一个锁,即保证线程任务同步!
package com.Thread.demo; import sun.security.jca.GetInstance; /** * 单例懒汉式的多线程操作的安全问题 * */ class Single{ //第一步:私有化构造函数 private Single(){ } //创建锁对象 private static Object lock = new Object(); //第二步:创建本类自己对象,初始化为空 public static Single instance =null; //对外提供一个公共方法,返回唯一对象 public static Single getInstance(){ <span style="color:#ff0000;">//加判断是提高后续线程的执行效率 if(instance==null){ //加同步的目的是保证对象的唯一 synchronized (lock) { if (instance==null) { instance =new Single(); } } }</span> //返回唯一的对象 return instance; } } //创建线程任务类,测试多线程操作单例的懒汉式的安全问题 class Task implements Runnable{ //复写run方法,书写线程任务 public void run() { //获取单例对象,,输出其地址 System.out.println(Single.getInstance()); } } public class SingleThreadDemo { public static void main(String[] args) { //创建任务对象 Task task= new Task(); //创建线程对象,将任务对象作为参数传递 Thread t1= new Thread(task); Thread t2= new Thread(task); //开启线程 t1.start(); t2.start(); } }
从上面结果可以看出当对线程任务添加锁后,即对两个线程操作的共同代码块同步以后,就可以办证单例在多线程操作中的安全。