一般用到最多的是强引用
如果一个对象没有强引用,只有软引用,当JVM发现内存不够时,垃圾回收器便会回收这些对象
如果一个对象只有弱引用时,每次垃圾回收都会被回收
如果一个对象仅持有幻影引用,那么它就和没有引用指向它一样,在任何时候该对象都可能被垃圾回收器回收。
幻影引用与软引用和弱引用的区别在于幻影引用必须和引用队列ReferenceQueue一起使用,幻影引用可以用来跟踪对象被回收的活动,因为当垃圾回收器准备回收一个对象的时候,如果发现它还有幻影引用,就会在回收之前,把这个幻影引用加入到与之关联的引用队列中去。
这样,程序通过判断引用队列中是否已经加入了幻影引用,来了解被引用对象是否将要被垃圾回收器回收,如果发现某个幻影引用已经被加入到引用队列,那么就可以在引用对象被回收之前采取必要的行动。
1、简介
ThreadLocal使用了弱引用,在一定程度上可以防止内存泄露。
2、ThreadLocal.ThreadLocalMap
此map使用的key是经过WeakReference包装的ThreadLocal对象,如果ThreadLocal对象没有其他强引用和弱引用指向时,线程也不会继续持有ThreadLocal对象,根据JVM规范,它会被垃圾回收器在下次回收时被销毁,这在一定程度避免了内存泄露。
/** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use * WeakReferences for keys. However, since reference queues are not * used, stale entries are guaranteed to be removed only when * the table starts running out of space. */ static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } }
最好使用remove方法,自己显示释放内存。
/** * 利用thread local 存取servlet * 每次request的通用数据 * @author caibosi * @created 2014-04-01 */ public class ThreadCache { private static final ThreadLocal<AppThreadContext> cache = new ThreadLocal<AppThreadContext>(){ @Override protected AppThreadContext initialValue() { return new AppThreadContext(); } }; private static class AppThreadContext{ String ip; String userName; Integer userId; long startTime; String hostName; String logId; Map<String,Object> extraData = new ConcurrentHashMap<String,Object>(); } public static void setIp(String ip){ cache.get().ip = ip; } public static String getIp(){ return cache.get().ip; } public static void setUserName(String userName){ cache.get().userName = userName; } public static String getUserName(){ return cache.get().userName; } public static void setUserId(Integer userId){ cache.get().userId = userId; } public static Integer getUserId(){ return cache.get().userId; } public static void setUser(Integer userId,String userName){ cache.get().userId = userId; cache.get().userName = userName; } public static void setExtraData(String key, Object data) { cache.get().extraData.put(key, data); } public static Object getExtraData(String key) { return cache.get().extraData.get(key); } public static void setStartTime(){ cache.get().startTime = System.currentTimeMillis(); } public static long getStartTime(){ return cache.get().startTime; } public static void setLogId(){ String logId = UUID.randomUUID().toString(); cache.get().logId = logId; } public static String getLogId(){ return cache.get().logId; } public static void setHostName(String hostName){ cache.get().hostName = hostName; } public static String getHostName(){ return cache.get().hostName; } public static void release() { cache.remove(); } }
使用及释放:
/** * @author caibosi * @created 2014-04-01 */ public class AclInterceptor extends HandlerInterceptorAdapter { private static final Logger logger = LoggerFactory.getLogger(AclInterceptor.class); @Resource private AntPathMatcher antPathMatcher; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //记录每次访问的时间 ThreadCache.setStartTime(); //记录host String hostname = null; try { hostname = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { logger.error(e.getMessage(), e); } if (hostname == null) { hostname = ""; } ThreadCache.setHostName(hostname); //url处理 String uri = request.getRequestURI(); // 静态资源不处理 if ("/favicon.ico".equals(uri) || antPathMatcher.match("/static/**", uri)) { return super.preHandle(request, response, handler); } request.setAttribute("_uri", uri); // 获取登录用户的ID和用户名信息 //sso或者登录跳转 //debug mode if(ConfigTool.isDebugEnv()){ ThreadCache.setUserId(ConfigTool.getDebugUserId()); } //进行权限校验 boolean hasUrlAccess = true; if(hasUrlAccess == false){ throw new AccessDeniedException("没有访问权限"); } return super.preHandle(request,response,handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { super.postHandle(request, response, handler, modelAndView); String uri = request.getRequestURI().replaceAll(";.*", ""); if (uri.endsWith(".ajax") && (uri.indexOf('.') != -1 || uri.indexOf("/cron/") != -1)) { return; } long time = ThreadCache.getStartTime(); if (time > 0) { long timeCost = System.currentTimeMillis() - time; logger.info("time used," + request.getRequestURI() + ",logId:" + ThreadCache.getLogId() + "," + timeCost + "ms"); request.setAttribute("_timeCost", timeCost); } //thread local资源释放 ThreadCache.release(); } }
/** * 封装了事务管理操作 * 主要是实现了事务嵌套的管理 * @author caibosi * @created 2013-10-29 */ public class TransManager { private final static Logger logger = LoggerFactory.getLogger(TransManager.class); private final static ThreadLocal<Transaction> transLocal = new ThreadLocal<Transaction>(); /** * 设置事务的隔离级别 * @param level */ public static void setTransactionViolation(TransactionLevel level){ Transaction tran = transLocal.get(); Connection conn = tran.getConn(); try { conn.setTransactionIsolation(level.getValue()); } catch (SQLException e) { logger.error("setting transaction violation failed",e); throw new RuntimeException("setting transaction violation failed",e); } } /** * 开启事务 */ public static void openTransaction(TransactionLevel level){ Transaction tran = transLocal.get(); if(tran==null){ tran = new Transaction(); Connection conn = DBManager.getConnection(); try { conn.setAutoCommit(false); if(level!=null && level.getValue()!= TransactionLevel.getDefault().getValue()){ conn.setTransactionIsolation(level.getValue()); } } catch (SQLException e) { logger.error("open transaction error",e); throw new RuntimeException("open transaction error"); } tran.setConn(conn); tran.setCommitCount(0); tran.setOpenCount(1); tran.setCurrentCount(1); transLocal.set(tran); } else{ tran.setOpenCount(tran.getOpenCount()+1); tran.setCurrentCount(tran.getCurrentCount()+1); } } /** * 提交事务 */ public static void commitTransaction(){ Transaction tran = transLocal.get(); if(tran == null) throw new RuntimeException("commit transaction , transaction null"); //判断要不要真正提交 if(tran.getCurrentCount()>1){ tran.setCommitCount(tran.getCommitCount() + 1); tran.setCurrentCount(tran.getCurrentCount()-1); return; } Connection conn = tran.getConn(); if(tran.canReallyCommit()){ try { conn.commit(); } catch (SQLException e) { logger.error("commit transaction error",e); throw new RuntimeException("commit transaction error"); } } } /** * 回滚事务 * 这里不真正回滚 * 做个标记 * 在close的时候判断是否要回滚 */ public static void rollbackTransaction(){ Transaction tran = transLocal.get(); // if(tran == null){ // logger.info("rollback trans null"); // return; // } tran.setCommitCount(0); } /** * 终止事务 */ public static void closeTransaction(){ Transaction tran = transLocal.get(); // if(tran == null){ // logger.info("close trans null"); // return; // } //如果当前还有1个以上的事务,不能真正关闭事务 if(tran.getCurrentCount()>1){ tran.setCommitCount(tran.getCurrentCount()-1); return; } //如果只剩一个事务,则真正结束事务,清理变量 Connection conn = tran.getConn(); if(tran.canReallyCommit()==false){ try { conn.rollback(); logger.info("#### rollback transaction"); } catch (SQLException e) { logger.error("rollback transaction failed",e); }finally{ transLocal.remove(); try { conn.close(); } catch (SQLException e) { logger.error("close conn failed",e); throw new RuntimeException("close conn failed",e); } } } } } /** * 封装了connection * 事务提交次数 * 事务嵌套层次 * 事务开启次数 * 用于控制事务嵌套 * @author caibosi * @created 2013-10-29 */ class Transaction { private Connection conn; /** * 统计事务次数 * 每开启一次,增加一次 * 用来与commitCount来判断 * 事务是否全部提交 */ private int openCount; /** * 提交次数 * 每提交一次,增加一次 */ private int commitCount; /** * 当前的事务数 * 开启一次增加1 * 提交一次减去1 */ private int currentCount; /** * 判断是否能够真正提交事务 * @return */ boolean canReallyCommit(){ return commitCount+1 == openCount; } Connection getConn() { return conn; } void setConn(Connection conn) { this.conn = conn; } int getCommitCount() { return commitCount; } void setCommitCount(int commitCount) { this.commitCount = commitCount; } int getOpenCount() { return openCount; } void setOpenCount(int openCount) { this.openCount = openCount; } int getCurrentCount() { return currentCount; } void setCurrentCount(int currentCount) { this.currentCount = currentCount; } }