保证一个类只有一个实例,而且提供一个访问该实例的全局访问入口java
1.Windows的任务管理器
2.Windows的回收站,也是一个单例应用
3.项目中的读取配置文件的对象
4.数据库的链接池
5.Servlet中的Application Servlet
6.Spring中的Bean默认也是单例的
7.SpringMVC Struts中的控制器程序员
1.因为单例模式只生成一个实例,减小了系统给的性能开销,当一个对象须要产生时,当时消耗的资源较多。那么产生对象时构建的方式就能够经过单例去构建。
2.单例模式存在全局访问点,因此能够优化共享资源访问。数据库
1.饿汉式:线程安全 调用率高 可是不能延迟加载
2.懒汉式:线程安全 调用率不高 可是能够延迟加载
3.双重检测(double check )
4.静态内部类(线程安全 能够延迟加载)
5.枚举单例 线程安全 不能够延迟加载安全
饿汉式bash
/*** 饿汉式:* 类只要被加载就会被加载全局变量,因此饿汉式,会被及时加载。(没有懒加载 )* 而且存在自然的线程安全问题。* @author 码歌老薛* @date 建立时间 猴年马月* @version 1.0*/public class SingleHungry {//提供静态的全局变量 做为访问该类实例的入口private static SingleHungry sh = new SingleHungry();/*** 构造器私有 没法建立对象*/private SingleHungry(){}/*** 对外提供get方法获取 该类的实例* @return*/public static SingleHungry getInstance(){return sh;}}复制代码 |
懒汉式jvm
/**
* 懒汉式:
* 全局变量初始化放到了实例化方法中,延迟产生对象。
* 可是当多个线程统一访问时,有可能出现线程不安全的状况。须要优化。
* @author 码歌老薛
* @date 建立时间 猴年马月
* @version 1.0
*/
public class SingleLazy implements Serializable{
//提供静态的全局变量 做为访问该类实例的入口 可是这里不当即加载
private static SingleLazy sh = null;
/**
* 构造器私有 没法建立对象
*/
private SingleLazy(){
System.out.println("构造函数被调用了");
}
/**
* 对外提供get方法获取 该类的实例
* @return
* @throws InterruptedException
*/
public static synchronized SingleLazy getInstance() {
if(sh==null){
sh = new SingleLazy();
}
return sh;
}
}
复制代码
上海尚学堂java培训 shsxt.com复制代码
双重检测函数
/**
* 懒汉式:
* 全局变量初始化放到了实例化方法中,延迟产生对象。
* 可是当多个线程统一访问时,有可能出现线程不安全的状况。须要优化。
* @author 码歌老薛
* @date 建立时间 猴年马月
* @version 1.0
*/
public class SingleLazy4 {
//提供静态的全局变量 做为访问该类实例的入口 可是这里不当即加载
private volatile static SingleLazy4 sh = null;
/**
* 构造器私有 没法建立对象
*/
private SingleLazy4(){
System.out.println("被调用了");
}
/**
* 双重校验锁式(也有人把双重校验锁式和懒汉式归为一类)分别在代码锁先后进行判空校验
* ,双重校验锁式是线程安全的。然而,在JDK1.5之前,DCL是不稳定的,有时也可能建立多个实例,
* 在1.5之后开始提供volatile关键字修饰变量来达到稳定效果。
* 双重校验锁DCL(double checked locking)
* @return
* @throws InterruptedException
*/
public static SingleLazy4 getInstance() {
if(sh == null){
synchronized(SingleLazy4.class){
if(sh == null){
sh = new SingleLazy4();
//return singleton; //有人提议在此处进行一次返回
}
//return singleton; //也有人提议在此处进行一次返回
}
}
return sh;
}
}
上海尚学堂Java培训 shsxt.com 获取更多java学习资料复制代码
静态内部类性能
/**
*静态内部类
*
* @author 码歌老薛
* @date 建立时间 猴年马月
* @version 1.0
*/
public class SingleInner {
/**
*静态内部类式和饿汉式同样,一样利用了ClassLoader的机制保证了线程安全;
*不一样的是,饿汉式在Singleton类被加载时(从代码段3-2的Class.forName可见)
*就建立了一个实例对象,而静态内部类即便Singleton类被加载也不会建立单例对象,
*除非调用里面的getInstance()方法。由于当Singleton类被加载时
*,其静态内部类SingletonHolder没有被主动使用。只有当调用getInstance方法时,
*才会装载SingletonHolder类,从而实例化单例对象。
这样,经过静态内部类的方法就实现了lazy loading,很好地将懒汉式和饿汉式结合起来,
既实现延迟加载,保证系统性能,也能保证线程安全
*/
private static class SingleInnerHolder{
private static SingleInner instance = new SingleInner();
}
private SingleInner(){
System.out.println("我被调用了");
}
public static SingleInner getInstance(){
return SingleInnerHolder.instance;
}
} 复制代码
枚举单例学习
/**
* jvm提供底层保证
* 不可能出现序列化、反射产生对象的漏洞 可是不能作到延迟加载
在外部,能够经过EnumSingleton.INSTANCE.work()来调用work方法。默认的枚举实例的建立是线程安全的
、,可是实例内的各类方法则须要程序员来保证线程安全。
总的来讲,使用枚举单例模式,有三个好处:
1.实例的建立线程安全,确保单例。2.防止被反射建立多个实例。3.没有序列化的问题。
* @author 码歌老薛
* @date 建立时间 猴年马月
* @version 1.0
*/
public enum SingleEnum {
//实例化对象
INSTANCE;
/**
* 对象须要执行的功能
*/
void getInstance(){
}
}
上海尚学堂java培训 shsxt.com复制代码
反射/序列化 获取对象 以及防止方式优化
import java.io.ObjectStreamException;
import java.io.Serializable;
/**
* 懒汉式:
* 全局变量初始化放到了实例化方法中,延迟产生对象。
* 可是当多个线程统一访问时,有可能出现线程不安全的状况。须要优化。
* @author 码歌老薛
* @date 建立时间 猴年马月
* @version 1.0
*/
public class SingleLazy implements Serializable{
//提供静态的全局变量 做为访问该类实例的入口 可是这里不当即加载
private static SingleLazy sh = null;
/**
* 构造器私有 没法建立对象
*/
private SingleLazy(){
if(sh!=null){
throw new RuntimeException();
}
System.out.println("构造函数被调用了");
}
/**
* 对外提供get方法获取 该类的实例
* @return
* @throws InterruptedException
*/
public static synchronized SingleLazy getInstance() {
if(sh==null){
sh = new SingleLazy();
}
return sh;
}
private Object readResolve()throws ObjectStreamException{
return sh;
}
}
复制代码
上海尚学堂java培训 shsxt.com复制代码
一、懒汉式效率是最低的。
二、占用资源少 不须要延时加载 枚举优于 饿汉式
三、占用资源比较多 须要延时加载 静态内部类 优于 懒汉式
更多Java技术文章欢迎阅读上海尚学堂Java培训,免费试学和线上公开课培训课程等你学习。