Java设计模式-单例
4种常用类型的单例:
1,饿汉单例 优势在于:类加载过程中默认线程安全 效率较高
2,懒汉单例 延时加载,有到的时候才回去加载,造成调用效率低,多个线程调用等待
3,静态内部类单例 静态内部类实现方式(懒加载)
4,枚举单例 天然的单例,因为枚举是基于JVM 天然避免了这样的问题,对于反射和反序列化不存在破解的问题
分别举例:
//饿汉式加载 类加载过程中默认线程安全
private static Single instance = new Single();
private Single(){
}
public static Single getInstance(){
return instance;
}
//延时加载,赖加载
private static Single1 instance;
private Single1(){
if (instance != null) {
throw new RuntimeException("单例只能加载一次");//防止反射重复 new instance 第二次new 抛异常
}
}
public static synchronized Single1 getInstance(){ //synchronized 造成调用效率低,多个线程调用等待
if (instance == null) {
instance = new Single1(); //延时加载,只有到用的时候才去加载
}
return instance;
}
//静态内部类实现方式(懒加载)
private static class Single2Instance {
private static Single2 instance = new Single2();
}
public static Single2 getInstance() {
return Single2Instance.instance;
}
private Single2 () {
}
//枚举天然就是一个单例子 但是不具备来加载的特点 枚举不可以通过反射,反序列化破解
public enum Single3 {
INSTANCE;
}
Single1 s1 = Single1.getInstance();
Single1 s2 = Single1.getInstance();
System.out.println(s1);
System.out.println(s2);
@SuppressWarnings("unchecked")
Class<Single1> clazz =
(Class<Single1>) Class.forName("com.sf.common.single.Single1"); /反射单例类
Constructor<Single1> c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);//反射可以通过设置setAccessible 访问私有的构造<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>
Single1 c1 = c.newInstance();
Single1 c2 = c.newInstance();可以抛出异常,防止反射<a href="https://www.jb51.cc/tag/diaoyong/" target="_blank" class="keywords">调用</a>单例私有的构造<a href="https://www.jb51.cc/tag/fangfa/" target="_blank" class="keywords">方法</a>
System.out.println(c1);
System.out.println(c2);
防止反序列化破解单例以及反破解的方法
首先 Single1 要实现一个 java.io.Serializable 方便实例化
Single1 s1 = Single1.getInstance();
Single1 s2 = Single1.getInstance();
System.out.println("s1 = " + s1);
System.out.println("s2 = " + s2);
//读文件到本地磁盘
FileOutputStream fos =
new FileOutputStream("e:/e.txt");
ObjectOutputStream oos =
new ObjectOutputStream(fos);
oos.writeObject(s1);
oos.close();
//从磁盘把内容写到控制台
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("e:/e.txt"));
Single1 s3 = (Single1) ois.readObject();
System.out.println(s3);//这样也可以破解单例,<a href="https://www.jb51.cc/tag/huoqu/" target="_blank" class="keywords">获取</a>了一个不一样的对象
}
如果要防止反射序列化 在单例里面加一个方法
//反序列化时 如果定义了readResolve 则直接返回此方法指定的对象,而不需要单独创建新对象
private Object readResolve() throws ObjectStreamException{
return instance;
}
测试几个单例各自耗费的时间:
int countNum = 10;
CountDownLatch down = new CountDownLatch(countNum);
long begin = System.currentTimeMillis();
for (int j = 0; j
需求:
每一个页面都需要地区代码,需要做一个公共的接口,让每一个页面都可以请求一个下拉框,提供选择,现在不仅需要显示下拉框,而且还需要设置定时任务,每30清空一个。
技术:Java Easyui
JAVA 代码片段:
public class CacheManager {
//实例化一个map,通过单例每次存取
private static Map> cacheMap = null;
private CacheManager() {}
public static Map<String,Collection<?>> getInstance() {
if(cacheMap == null){
cacheMap = new HashMap<String,Collection<?>>();
}
return cacheMap;
}
//判断map 并且定时清空
public static void clearOfKey(String key){
if (cacheMap != null && cacheMap.containsKey(key)) {
cacheMap.remove(key);
}
}
}
定时任务定时调用 根据key清空,每30min清空一次
@Component
public class SysTask {
@Scheduled(cron = "0 0/30 * * * ?")
public void cleanAreaCodeCache(){
CacheManager.clearOfKey(CacheEmun.DEPTCACHE.getKey());
}
}
定义唯一Map的键 枚举类型
public enum CacheEmun {
DEPTCACHE("GLOBLE_DEPT_TMP_CACHE");
private String key;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
private CacheEmun(String key) {
this.key = key;
}
}
Action 请求数据库 加缓存处理
public Collection loadDepartment() {
Collection deptCollections = null;//初始化集合
//判断集合为空
if (!CacheManager.getInstance().containsKey(CacheEmun.DEPTCACHE.getKey())) {
deptCollections = departmentDao.loadDepts();
deptCollections.forEach(items -> items.setDeptName(items.getAreaCode()+ "/" + items.getDeptName()));
CacheManager.getInstance().put(CacheEmun.DEPTCACHE.getKey(),deptCollections);
}else{
deptCollections = (Collection) CacheManager.getInstance().get(CacheEmun.DEPTCACHE.getKey());
}
return deptCollections;
}
原文链接:https://www.f2er.com/note/421453.html