单例模式
2016-04-02 17:11
393 查看
1.单例模式定义
保证一个类仅有一个实例,并提供一个访问它的方法2.UML建模图:
3.懒汉式
//等到要使用实例的时候才会创建 public class LazySingleton { private static LazySingleton uniqueInstance = null; private String data; private LazySingleton(){ } public static synchronized LazySingleton getInstance(){ if(null == uniqueInstance){ uniqueInstance = new LazySingleton(); } return uniqueInstance; } public String getData() { return data; } public void setData(String data) { this.data = data; } }
4.饿汉式
//类加载的时候初始化 public class HungrySingleton { private static HungrySingleton hungrySingleton = new HungrySingleton(); private String data; public String getData() { return data; } public void setData(String data) { this.data = data; } //构造方法 private HungrySingleton(){ } private static HungrySingleton getInstance(){ return hungrySingleton; } }
5.线程安全问题
饿汉式是线程安全的,在装载类的时候不会发生并发懒汉式:
解决方法
1. public static synchronized Singleton getInstance(){} 在多线程环境下,效率很低。
2. 双重锁 Double Check Locking
volatile在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值
//volatile private volatile static Singleton uniqueInstance = null; private Singleton(){} public static Singleton getInstance(){ if(uniqueInstance == null){ //同步块 synchronized(Singleton.class){ if(uniqueInstance == null){ uniqueInstance = new Singleton(); } } } return uniqueInstance; }
内部类
private static class SingletonHolder{ private static Singleton instance = new Singleton(); } private Singleton(){} public static Singleton getInstance(){ return SingletonHolder.instance; }
枚举类
public enum Singleton{ uniqueInstancde; public void singletonOperation(){} }
6.真的只有一个对象么
其实,单例模式并不能保证实例的唯一性,只要我们想办法的话,还是可以打破这种唯一性的。以下几种方法都能实现。1).使用反射,虽然构造器(newInstance)为非公开,但是在反射面前就不起作用了。
2).如果单例的类实现了cloneable,那么还是可以拷贝出多个实例的。
参考链接
3).Java中的对象序列化也有可能导致创建多个实例。避免使用readObject方法。因为通过序列化来生成对象时,无需调用构造器,读出的对象和写入的对象不相等(==)。这种单例的情况可以通过readResolve来解决,替换readObject读到的对象。
4).使用多个类加载器加载单例类,也会导致创建多个实例并存的问题。
7. 单例的扩展–只生成3个实例
/** * 扩展单例模式,控制实际产生实例数目为 3 个 */ public class ThreeSingleton { //为后面使用的 key 定义一个前缀 private final static String DEFAULT_KEY = "cache"; //定义缓存实例的容器 private static Map<String,ThreeSingleton> map = new HashMap<>(); private static int number = 1;//定义初始化实例数目为 1 private final static int NUM_MAX = 3; private ThreeSingleton(){ } public static synchronized ThreeSingleton getInstance(){ //通过缓存理念及方式控制数量 String key = DEFAULT_PREKEY + number; ThreeSingleton threeSingleton = map.get(key); if(threeSingleton == null){ threeSingleton = new ThreeSingleton(); map.put(key, threeSingleton); } number++;//实例数目加 1 if(number > NUM_MAX){ number=1; } return threeSingleton; } public static void main(String args[]){ ThreeSingleton t1 = getInstance(); ThreeSingleton t2 = getInstance(); ThreeSingleton t3 = getInstance(); ThreeSingleton t4 = getInstance(); ThreeSingleton t5 = getInstance(); ThreeSingleton t6 = getInstance(); System.out.println(t1.toString()); System.out.println(t2.toString()); System.out.println(t3.toString()); System.out.println(t4.toString()); System.out.println(t5.toString()); System.out.println(t6.toString()); } }
8. Java多线程(第六章)
如何使单例模式遇到多线程是安全的,正确的?1. 立即加载(饿汉模式):在调用方法前,实例已经被创建
2. 延迟加载(懒汉模式):等到调用方法时,实例才被创建
相关文章推荐
- CSS Reset
- Linux内核分析——第十八章 调试
- Zookeeper + Hadoop2.6 集群HA + spark1.6完整搭建与所有参数解析
- Java学习路线图
- linux下lighttpdserver的具体安装步骤 以及对flv流媒体的支持配置
- 分布式存储概述
- Problem K: 反序数
- 剑指offer:找到二叉树中序遍历的下一个节点
- hdoj 素数回文 1431 (模拟)
- C 【printf 和 scanf 函数的使用】
- 给突然没有动力的自己看看
- SDAU课程练习2 1020
- hdu 2923 Einbahnstrasse 最短路spfa+map容器
- 关于jQuery绑定事件会叠加的解决和心得总结
- Linux下Oracle开机自启动
- 全景VR视频外包公司:长年承接VR全景视频外包(技术分享YouTube的360全景视频)
- Random Forests (随机森林)
- China Agricultural University 网关流量监控系统
- Problem J: 用递归求和。1+2+3+4+....n.
- Why does “extern const int n;” not work as expected?