java设计模式-单例模式
@(JAVA设计模式)
作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
单例模式是java设计之中最简单的设计模式之一。
==单利模式==属于==创建型==模式,其提供了创建对象的是最佳方法。
单例模式核心:
- 单例类==只能有一个实例==
- 单例类必须自己创建自己的唯一实例
- 单例类必须给所有其他对象提供这一实例。
单例模式介绍:
- 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
- 主要解决:一个全局使用的类频繁地创建与销毁。
- 何时使用:当您想控制实例数目,节省系统资源的时候。
- 如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
- 关键代码:构造函数是私有的。
优点:
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
- 避免对资源的多重占用(比如写文件操作)。
缺点
- 没有接口,不能继承,与单一职责原则冲突
- 一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
何时使用单例模式?
- 要求生产唯一序列号。
- WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
饿汉式单例类:
又何为饿?饿者,饥不择食;但凡有食,必急食之。
此处同义:在加载类的时候就会创建类的单例,并保存在类中。
该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了。
实例:使用懒汉模式模拟产生总统对象。
分析:总统只能为一人,所以适用于懒汉模式(单例模式)。
package 单例模式.饿汉式;
/**
* @author HP
*/
public class EHanShi {
/**将构造方法私有化,不允许外部直接创建对象*/
private EHanShi(){}
/**创建类的唯一实例,使用private static进行修饰*/
private static EHanShi instance=new EHanShi();
/**提供一个用于获取实例的方法,使用public static 修饰*/
public static EHanShi getInstance(){
return instance;
}
public void ShowMessage(){
System.out.println("饿汉模式");
}
public static class getInstance extends EHanShi {
}
}
饿汉式是:类在被加载的时候,静态变量会被初始化,而且类的私有化构造子类会被调用,在此刻单例类的唯一实例被创建出来。
(⊙o⊙)…………
饿汉模式是在开始很饿迫不及待的想吃到东西,所以创建实例的时候比较着急,于是就在装载类的时候就创建了对象实例。
==private static EHanShi instance=new EHanShi();==
饿汉模式就是典型的以==空间==来交换==时间==的思想,当类在装载的时候就创建类的实例,不用在乎后期是否需要使用,先创建,然后每次调用的时候就不需要判断,节省了运行时间。即:牺牲空间来换取运行时间。
懒汉式单例类:
懒汉式:实现了对静态工厂方法使用了同步化,用来处理多线程环境。
懒汉懒汉,以懒惰为前提,可以拖后的事情一定不想先搞。所以懒汉模式就是在创建对象实例的时候不用着急创建,一直到需要使用对象实例的时候才开始创建,总归为“懒”。
如下:
private static Layz instance=null;
懒汉模式是典型的用时间换取空间的思想
在每次获取实例的时候判断是否需要创建实例对象,所以浪费的时间是用于判断。当无人使用实例对象的时候,便可以不用创建,节约内存空间。
懒汉式的实现相较于饿汉式是线程安全的,但会造成整体的访问速度降低,判断次数过多。
package 单例模式.懒汉式;
public class Lazy{
/**1.将构造方式私有化,不允许外边直接创建对象*/
private Lazy(){
System.out.println("产生一个总统");
}
/**2.声明类的唯一实例,使用private static修饰*/
private static Lazy instance=null;
/**3.提供一个用于获取实例的方法,使用public static修饰*/
public static Lazy getInstance(){
if(instance==null){
instance=new Lazy();
}
else{
System.out.println("已经有一个总统,不能产生新总统!");
}
return instance;
}
public void getName(){
System.out.println("我是美国总统");
}
/**优化 进程同步*/
public static synchronized Lazy getInstance1(){
if (instance==null){
instance=new Lazy();
}
else
{
System.out.println("已经有一个总统,不能产生新总统!");
}
return instance;
}
}
懒汉式优化:
双重检查加锁:
并不是每次进入getInstance
方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
public class EHanShi1 {
private volatile static EHanShi1 instance = null;
private EHanShi1(){}
public static EHanShi1 getInstance(){
//先检查实例是否存在,如果不存在才进入下面的同步块
if(instance == null){
//同步块,线程安全的创建实例
synchronized (EHanShi1.class) {
//再次检查实例是否存在,如果不存在才真正的创建实例
if(instance == null){
instance = new EHanShi1();
}
}
}
return instance;
}
}
==volatile==,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
文章制作:瑾墨
有错误的地方欢迎指正。