先看看什么是单例设计模式呢?
单例设计模式,也称单态(原子)设计模式。最初起始于建筑行业,建筑行业把建筑中中的一些常见问题进行了归纳总结,并给出了具体的解决方案。(简单理解就是解决问题的模板)
单例设计模式 ,是用来解决:程序中的所创建出来的对象只有一个(创建的对象在堆内存中只开辟一个空间)。
问题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();
}
}
从上面结果可以看出当对线程任务添加锁后,即对两个线程操作的共同代码块同步以后,就可以办证单例在多线程操作中的安全。