单例模式的使用
单例创建用户服务对象没必要给每个用户都创建一个
单例 :1 构造方法私有化
2 创建一个私有的静态变量
3 公共的静态方法 当做入口
第一种单例模式
问题 : 预先加载,没有手动实例化变量的时候 已经实例化了变量
当你要使用对象的时候,只是把这个变量给你,构造方法私有化 外界不能直接访问。
private UserService(){ // 创建一个私有的静态变量(常量) private static final UserService USER_SERVICE = new UserService(); // 3对外提供一个 公共的 静态的 返回该对象实例的一个方法 public static UserService getInstance(){ return USER_SERVICE; } }
懒汉式
/** * 懒汉式 写法1
* 重大缺陷:线程不安全 * @author Administrator */ public class Singleton {
//私有化构造函数 private Singleton(){ } private static Singleton singleton=null; //静态工厂方法 public static Singleton getInstance(){ if(singleton==null){ singleton=new Singleton(); } return singleton; } }
饿汉式
/** * 饿汉式:类初始化时,实例化。 * @author Administrator * 类初始化时开销大,线程安全 */ public class Singleton3 { private Singleton3(){ } private static final Singleton3 singleton=new Singleton3(); public static Singleton3 getInstance(){ return singleton; } }
第二种同步懒汉式
问题: 排队严重 严重影响效率
因为每个用户在计算机里面都是一个单独的线程
当 一个线程 调用UserService 对象以后加了一把锁,别人就访问不了了
/** * 单例模式的目标是什么? * 是为了让当前类只能产生一个对象 如果 我先后创建了多个还是单例吗?. */ private UserService(){ //构造方法私有化 private static UserService userService = null; //先创建一个 静态变量 public static synchronized UserService getInstance(){ if(userService == null){ //如果为空 我返回一个新的 userService = new UserService(); } return userService; //如果不为空 直接返回 }
第三种
/** * 如果两个线程同时判断了userService是空 进去了 第一个线程创建的疏忽,锁住了,第二个需要瞪大,第一个线程创建完了之后 * 本来是第二个,我不需要再创建了 ,但是他已经在判断里面了,所以又创建了一个 ,所以说,单例模式没有成功 * @param user */ private UserService(){ //构造方法私有化 private static UserService userService = null; public static UserService getInstance() { if(userService == null){//如果两个或多个线程同时进入这里,判断完成后都为空,那么会创建好多对象吧,单例模式就失效了 synchronized(UserService.class){//我现在对整个类锁了
userService = new UserService(); } } return userService; }
第四种 双重检测懒汉式
private UserService() { // 构造方法私有化 private static volatile UserService userService = null;// 私有的静态变量 public static UserService getInstance() {// 获取当前类对象的方法 if (userService == null) { synchronized (UserService.class) {// 现在是对整个类锁住了 if (userService == null) {// 更上面第三章方法一样,当前就能解决第三种方法的问题(创建了多个对象),因为,就是两个同时进入上面的if判断,到这里,就会判断不通过,就会直接返回一个对象,不会在去创建新的对象 userService = new UserService(); } } } return userService; }
在双重检测中,使用了 volatile 关键字,能够保证访问到的变量是最后修改的。为什么要加volatile关键字呢?因为在Java中双重
检测很可能导致失败的结果,得到一个存在但未初始化完成的实例。《Java与模式》的总结是:在Java编译器中,Singleton类的初
始化与instance变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取instance引用,并调用这个对象的方法的
话,可能会发现对象初始化过程尚未完成,从而造成崩溃。
第五种 静态内部类
/** * 懒汉式:通过静态内部类实现方式,既实现了线程安全,又提高了效率 * @author Administrator * */ public class Singleton4 { private Singleton4(){ } public static Singleton4 getInstance(){ return Instance.singleton; //当需要返回实例的时候,初始化创建静态实例对象。 } private static class Instance{ private static final Singleton4 singleton=new Singleton4(); } }
第六种 Enum枚举实现
/** * 枚举类型实现单例 * @author Administrator * */ public class Singleton5 { public enum Singleton{ INSTANCE; public void method(){ //任意方法 } } public static void main(String[] args) { Singleton.INSTANCE.method(); } }
枚举方法 简洁明了,并提供序列化机制,不会在反序列化实例时创建新实例(在其他单例方法中如果要变成可序列化的,不仅要加
上implements Serializable,还需要提供readResolve方法,参加《effective Java》)。也不会受到反射机制的影响,是实现单例
模式的最佳方法。