一、引用类型
1、强引用(Strong Reference)
一般用到最多的是强引用
2、软引用(Soft Reference)
如果一个对象没有强引用,只有软引用,当JVM发现内存不够时,垃圾回收器便会回收这些对象
3、弱引用(Weak Reference)
如果一个对象只有弱引用时,每次垃圾回收都会被回收
4、幻影引用(Phantom Reference)
如果一个对象仅持有幻影引用,那么它就和没有引用指向它一样,在任何时候该对象都可能被垃圾回收器回收。
幻影引用与软引用和弱引用的区别在于幻影引用必须和引用队列ReferenceQueue一起使用,幻影引用可以用来跟踪对象被回收的活动,因为当垃圾回收器准备回收一个对象的时候,如果发现它还有幻影引用,就会在回收之前,把这个幻影引用加入到与之关联的引用队列中去。
这样,程序通过判断引用队列中是否已经加入了幻影引用,来了解被引用对象是否将要被垃圾回收器回收,如果发现某个幻影引用已经被加入到引用队列,那么就可以在引用对象被回收之前采取必要的行动。
二、ThreadLocal
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方法,自己显示释放内存。
三、ThreadLocal应用
(1)ThreadCache
/**
* 利用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();
}
}
(2)事务嵌套
/**
* 封装了事务管理操作
* 主要是实现了事务嵌套的管理
* @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;
}
}
来源:oschina
链接:https://my.oschina.net/u/1383356/blog/282675