Java中的强引用,软引用,弱引用,虚引用有什么用?
29 个回答
ThreadLocal中,获取到线程私有对象是通过线程持有的一个threadLocalMap,然后传入ThreadLocal当做key获取到对象的,这时候就有个问题,如果你在使用完ThreadLocal之后,将其置为null,这时候这个对象并不能被回收,因为他还有 ThreadLocalMap->entry->key的引用,直到该线程被销毁,但是这个线程很可能会被放到线程池中不会被销毁,这就产生了内存泄露,jdk是通过弱引用来解决的这个问题的,entry中对key的引用是弱引用,当你取消了ThreadLocal的强引用之后,他就只剩下一个弱引用了,所以也会被回收。
-----------------------
理论再多不如应用来的实际;
WeakReference使用实例:
ThreadLocalMap类 该类时ThreadLocal的静态内部类,该Map使用开放地址法处理hash冲突的Map类,key为ThreadLocal对象,value为TheadLocal对象所对应的值value;
其中Entry对象当中的Key值对TheadLocal的引用就是WeakReference
static class Entry extends WeakReference<ThreadLocal>
{
/* The value assocaiated with this ThreadLocal.*/
Object value;
Entry(ThreadLocal k,Object v)
{
super(k);
value = v;
}
}
这样当ThreadLocal对象除了Entry对象外没有其他引用的时候,在下一次垃圾回收发生时,该对象将被回收;
这也就导致在使用Entry对象获取key值得时候,需要判断是否为空,如果为空,则说明已经被回收了,此时将value值手动清除即可;
其实因为ThreadLocal牵涉到线程本地变量的操作,对于对象何时被清除,程序逻辑一般不太好实现,所以JDK设计者将其设置为了自动清除,
其实大部分TheadLocal对象我们都将其设置为private static 对象,一般不会被弱引用清除掉;
具体更为详细的内容请查询ThreadLocal
------------------------
SoftReference
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
// be very careful not to change the stack depth of this
// checkMemberAccess call for security reasons
// see java.lang.SecurityManager.checkMemberAccess
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Method method = getMethod0(name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(getName() + "." +
name + argumentTypesToString(parameterTypes));
}
return method;
}
下面看调用的getMethod0
private Method getMethod0(String name, Class<?>[] parameterTypes) {
// Note: the intent is that the search algorithm this routine
// uses be equivalent to the ordering imposed by
// privateGetPublicMethods(). It fetches only the declared
// public methods for each class, however, to reduce the
// number of Method objects which have to be created for the
// common case where the method being requested is declared in
// the class which is being queried.
Method res;
// Search declared public methods
if ((res = searchMethods(privateGetDeclaredMethods(true),
name,
parameterTypes)) != null) {
return res;
}
// Search superclass's methods
if (!isInterface()) {
Class<? super T> c = getSuperclass();
if (c != null) {
if ((res = c.getMethod0(name, parameterTypes)) != null) {
return res;
}
}
}
// Search superinterfaces' methods
Class<?>[] interfaces = getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
Class<?> c = interfaces[i];
if ((res = c.getMethod0(name, parameterTypes)) != null) {
return res;
}
}
// Not found
return null;
}
下面看调用的privateGetDeclaredMethods
/**
* 获取类中声明方法的具体实现
* @param publicOnly 是否只获取public方法
* @return 方法数组
*/
private Method[] privateGetDeclaredMethods(boolean publicOnly) {
// 等待系统内部类初始化完成,系统属性(sun.reflect.noCaches)被解析完成
checkInitted();
Method[] res = null;
// 根据用户指定的系统属性sun.reflect.noCaches值来决定是否使用缓存,默认使用缓存
if (useCaches) {
// 清空缓存,将缓存的declaredFields、declaredMethods、annotations等设置为null
clearCachesOnClassRedefinition();
// 如果只获取public方法
if (publicOnly) {
// 如果declaredPublicFields缓存可用,则直接从缓存中获取
if (declaredPublicMethods != null) {
res = (Method[]) declaredPublicMethods.get();
}
} else {
// 如果declaredMethods缓存可用,则直接从缓存中获取
if (declaredMethods != null) {
res = (Method[]) declaredMethods.get();
}
}
if (res != null) return res;
}
// 不使用缓存,则需要调用本地方法进行获取
res = getDeclaredMethods0(publicOnly);
// 如果可以使用缓存,则设置缓存,以备下次使用
if (useCaches) {
if (publicOnly) {
declaredPublicMethods = new SoftReference(res);
} else {
declaredMethods = new SoftReference(res);
}
}
return res;
}
其中 declaredPublicMethods就是一个SoftReference
我们来看下这个成员变量的定义
private volatile transient SoftReference declaredPublicMethods;
private volatile transient SoftReference declaredMethods;
if(publicOnly){
// 如果declaredPublicFields缓存可用,则直接从缓存中获取
if(declaredPublicMethods != null){
res =(Method[]) declaredPublicMethods.get();
}
}else{
// 如果declaredMethods缓存可用,则直接从缓存中获取
if(declaredMethods != null){
res =(Method[]) declaredMethods.get();
}
}
其中res就是要获取的Method[] res 方法数组
如果发现get的结果已经为空,说明没有初始化或者已经被GC掉了,就重新获取一份新的并设置即可;
所以SoftReference非常适合用于做不是很重要的数据缓存,当内存紧张时,可以被GC掉
其实SoftReference和WeakReference都经常用来作为缓存来使用,不过WeakReference更容易被清除而已。
下面的文章也有详细的介绍