###java最全单例模式
定义;
确保某一个类只有一个实例,并且自行实例化并且向整个系统提供这个实例
实现单例模式有几个比较重要的关键点:
- 构造的函数一般不对外进行开放,使用private私有属性
- 通过一个静态方法或者枚举返回单例对象
- 确保单例类的对象有且只有一个,尤其是在多线程下,一定要保持线程的安全
- 确保单例类对象子反序列化的时候不会重新构建对象
单例模式分类:
- 饿汉式单例模式
- 懒汉式单例模式
- 双重检查锁实现单例
- 静态内部类来实现单例模式
- 使用枚举类型来实现单例
- 使用容器的形式来实现单例子模式
饿汉式单例模式
在静态代码块中去new对象, 但是线程不安全,在不使用的时候,其实对象也已经实例化了
package com.example.zzf.single;
import java.io.ObjectStreamException;
/**
* 饿汉式单例模式
* 在静态代码块中去new对象,
* 但是线程不安全,在不使用的时候,其实对象也已经实例化了
* @author Administrator
*
*/
public class SingleTonOne {
private static final SingleTonOne singleTonOne = new SingleTonOne();
private SingleTonOne(){
}
public static SingleTonOne getInstance(){
return singleTonOne;
}
public void doSomething(){
System.out.println("this is SingleTonOne");
}
/**
* 防止单例对象在序列化后,再次反序列化后生成不同的对象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return singleTonOne;
}
}
####懒汉式单例模式
优点:在实例化的时候去new对象,线程安全
缺点:每一次使用的时候都需要进行同步一次,这样会过多的消耗资源
package com.example.zzf.single;
import java.io.ObjectStreamException;
/**
* 懒汉式单例模式
* 优点:在实例化的时候去new对象,线程安全
* 缺点:每一次使用的时候都需要进行同步一次,这样会过多的消耗资源
* @author Administrator
*
*/
public class SingleTonTwo {
private static SingleTonTwo singleTonTwo;
private SingleTonTwo(){
}
public static synchronized SingleTonTwo getInstance(){
if(singleTonTwo == null){
singleTonTwo = new SingleTonTwo();
}
return singleTonTwo;
}
public void doSomething(){
System.out.println("this is SingleTonTwo");
}
/**
* 防止单例对象在序列化后,再次反序列化后生成不同的对象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return singleTonTwo;
}
}
####双重检查锁实现单例
优点:在需要的时候才去实例化,而且能保证线程的安全行,而且单例模式在初始化后,就不会在进行同步,也不会过多的消耗资源
缺点:第一次在加载的时候会加载稍微慢一点,双重检查锁失效可能会出现单例实现有问题
package com.example.zzf.single;
import java.io.ObjectStreamException;
/**
* 双重检查锁实现单例
* 有点:在需要的时候才去实例化,而且能保证线程的安全行,而且单例模式在初始化后,就不会在进行同步,也不会过多的消耗资源
* 缺点:第一次在加载的时候会加载稍微慢一点
* @author Administrator
*
*/
public class SingleTonThree {
private static SingleTonThree sInstance = null;
// private static volatile SingleTonThree sInstance = null; //从主内存中读取,会影响性能
private SingleTonThree(){
}
public static SingleTonThree getInstance(){
if(sInstance == null){
synchronized (SingleTonThree.class) {
if(sInstance == null){
sInstance = new SingleTonThree();
}
return sInstance;
}
}
return sInstance;
}
public void doSomething(){
System.out.println("this is SingleTonThree");
}
/**
* 防止单例对象在序列化后,再次反序列化后生成不同的对象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return sInstance;
}
}
静态内部类来实现单例模式
由于双重检查锁在高并发或者因为内存模型的原因,有时候偶尔会失效,所以推荐使用静态内部类来实现单例模式
第一次加载的时候不会初始化SingleTonFour,只有第一次调用getInstance的时候才会去创建对象,
既保证了线程安全性么也保证对象唯一性,同时延迟了单例的实例化
package com.example.zzf.single;
import java.io.ObjectStreamException;
/**
* 静态内部类来实现单例莫斯
* 由于双重检查锁在高并发或者因为内存模型的原因,有时候偶尔会失效,所以推荐使用静态内部类来实现单例模式
* 第一次加载的时候不会初始化SingleTonFour,只有第一次调用getInstance的时候才会去创建对象,
* 既保证了线程安全性么也保证对象唯一性,同事延迟了单利的实例化
* @author Administrator
*
*/
public class SingleTonFour {
private SingleTonFour(){
}
public static SingleTonFour getInstance(){
return SingleTonFourHolder.singleTonFour;
}
private static class SingleTonFourHolder{
private static final SingleTonFour singleTonFour = new SingleTonFour();
}
public void doSomething(){
System.out.println("this is SingleTonFour");
}
/**
* 防止单例对象在序列化后,再次反序列化后生成不同的对象
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException{
return SingleTonFourHolder.singleTonFour;
}
}
####使用枚举类型来实现单例
好处:枚举在java中就和普通的类型是一样的,不仅能够有字段,还可以有自己的方法,最主要的就是枚举类型实例的创建默认是线程安全的,在任何一种情况下他都只会有一个实例
package com.example.zzf.single;
/**
* 使用枚举类型来实现单例
* 好处:枚举在java中就和普通的类型是一样的,不仅能够有字段,还可以有自己的方法,最主要的就是枚举类型实例的创建默认是线程安全的,在任何一种情况下他都只会有一个实例
*
* @author Administrator
*
*/
public enum SingleTonEnum {
INSTANCE;
public void doSomething(){
System.out.println("this is SingleTonEnum!");
}
}
####使用容器的形式来实现单例子模式
将多个单例类型全部注入到一个管理类中进行统一管理,根据需求来选择
package com.example.zzf.single;
/**
* 使用容器的形式来实现单例子模式
* 将多个单例类型全部注入到一个管理类中进行统一管理,根据需求来选择
*
*/
import java.util.HashMap;
import java.util.Map;
public class SingleTonManager {
private static Map<String,Object> objectMap = new HashMap();
private SingleTonManager(){
}
public static void registerSingleServer(String key,Object instance){
if(!objectMap.containsKey(key)){
objectMap.put(key, instance);
}
}
public static Object getSingleService(String key){
return objectMap.get(key);
}
}
MainTest.java中的代码:
package com.example.zzf;
import com.example.zzf.single.SingleTonEnum;
import com.example.zzf.single.SingleTonFour;
import com.example.zzf.single.SingleTonManager;
import com.example.zzf.single.SingleTonOne;
import com.example.zzf.single.SingleTonThree;
import com.example.zzf.single.SingleTonTwo;
public class MainTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
SingleTonOne singleTonOne = SingleTonOne.getInstance();
singleTonOne.doSomething();
SingleTonManager.registerSingleServer("SingleTonOne", singleTonOne);
SingleTonTwo singleTonTwo = SingleTonTwo.getInstance();
singleTonTwo.doSomething();
SingleTonManager.registerSingleServer("SingleTonTwo", singleTonTwo);
SingleTonThree singleTonThree = SingleTonThree.getInstance();
singleTonThree.doSomething();
SingleTonManager.registerSingleServer("SingleTonThree", singleTonThree);
SingleTonFour singleTonFour = SingleTonFour.getInstance();
singleTonFour.doSomething();
SingleTonManager.registerSingleServer("SingleTonFour", singleTonFour);
SingleTonEnum singleEnum = SingleTonEnum.INSTANCE;
singleEnum.doSomething();
SingleTonManager.registerSingleServer("SingleTonEnum", singleEnum);
System.out.println("===========================================");
singleTonOne = (SingleTonOne) (SingleTonManager.getSingleService("SingleTonOne"));
singleTonTwo = (SingleTonTwo) SingleTonManager.getSingleService("SingleTonTwo");
singleTonThree = (SingleTonThree) SingleTonManager.getSingleService("SingleTonThree");
singleTonFour = (SingleTonFour) SingleTonManager.getSingleService("SingleTonFour");
singleEnum = (SingleTonEnum) SingleTonManager.getSingleService("SingleTonEnum");
singleTonOne.doSomething();
singleTonTwo.doSomething();
singleTonThree.doSomething();
singleTonFour.doSomething();
singleEnum.doSomething();
}
}
这些都是一些很简单的理解和总结,希望这些能够帮助到大家:
源码下载地址:源代码下载