单例模式
一、概述
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式
二、单例设计模式(Singleton)
采取一定的方法保证在软件系统中对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们让类在虚拟机中只产生一个对象,首先必须将类的构造器私有化(private),这样就不能用new操作符在类的外部产生该类的对象,但在类的内部仍可以产生类的对象。因为在类的外部开始无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以该类内部产生的该类对象的变量必须定义为静态。
三、实现
1、饿汉式
public class SingletonTest {
public static void main(String[] args) {
Bank instance1 = Bank.getInstance();
Bank instance2 = Bank.getInstance();
}
}
/**
* 饿汉式
*/
class Bank{
/**
* 1、私有化构造器
*/
private Bank(){
}
/**
* 2.内部创建类的对象
*/
private static Bank instance=new Bank();
/**
* 3、提供公共的方法,返回类的对象
*/
public static Bank getInstance(){
return instance;
}
}
2、懒汉式
public class SingletonTest2 {
public static void main(String[] args) {
Bank instance = Bank.getInstance();
}
}
/**
* 懒汉式
*/
class Order{
/**
* 1、私有化类的构造器
*/
private Order(){
}
/**
* 2、声明当前类的对象,没有初始化
*/
private static Order instance=null;
/**
* 3、声明public、static的返回当前类的对象
* @return
*/
public static Order getInstance(){
if(instance==null){
instance=new Order();
}
return instance;
}
}
3、区别
- 懒汉式:优点:延迟对象的创建。缺点:线程不安全
- 饿汉式:优点:线程安全。缺点:对象加载时间过长。
四、双重校验锁
1. volatile关键字
- 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
- 禁止指令重排序
2. 代码演示
public class Sington {
public static void main(String[] args) {
}
private static volatile Sington SINGTON;
public static Sington getInstance() {
//使用volatile修饰SINGTON保证可见性,提高效率
if (SINGTON == null) {//①
synchronized (Sington.class) {//保证原子性
//为了保证单例,返回的是同一个对象
if (SINGTON == null) {
//② 分配内存空间
//③ 初始化对象
//④ 赋值给变量
SINGTON = new Sington();
}
}
}
return SINGTON;
}
}
- 注意:假设SINGTON不加volatile修饰
- 在new对象的时候指令可分解为代码中的三步
- 若此时先执行步骤②和④,此时变量SINGTON已经有值,但它不是Sington()的实例
- 此时步骤①处判断SINGTON!=null,则返回的对象就会出错,因为不是Sington()的对象
五、使用场景
单例模式是生成一个实例,减少系统性能开销,当一个对象产生需要多的资源时,如读取配置。产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留在内存当中。
- 网站的计数器:一般为单例模式,否则难以同步
- 应用程序的日志应用:由于共享日志文件一直处于打开状态,只能有一个实例去操作,否则能容不好追加
- 数据库连接池:数据库连接是一种数据库资源
- Windows的任务管理器
- Windows的Recycle Bin(回收站):系统运行过程中回收站一直维护着仅有的一个实例。