微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Java 设计模式-单例以及应用案例-运用单例设置临时缓存

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>
Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.out.println(c1);
Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.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();
Sy<a href="https://www.jb51.cc/tag/stem/" target="_blank" class="keywords">stem</a>.out.println(s3);//这样也可以破解单例,<a href="https://www.jb51.cc/tag/huoqu/" target="_blank" class="keywords">获取</a>了<a href="https://www.jb51.cc/tag/yige/" 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; jstem.currentTimeMillis();
 System.out.println("花费时间:"+(end-begin));
}

需求:
一个页面都需要地区代码,需要做一个公共的接口,让每一个页面都可以请求一个下拉框,提供选择,现在不仅需要显示下拉框,而且还需要设置定时任务,每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;
 } 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐