一、Java中的强、软、弱、虚引用

在JDK中我们能够看到有一个java.lang.ref的包。这个包中就是Java中实现强、软、弱、虚引用的包,例如以下:

PhantomReference

虚引用:假设一个对象持有虚引用,就和没有持有引用一样,在不论什么时候都可能被垃圾回收器回收。

虚引用主要用来跟踪对象被垃圾回收的活动,虚引用另一个和弱、软引用不同的地方是虚引用必须和引用队列联合使用。当垃圾回收器准备回收一个对象时。假设发现它还有虚引用,就会在回收对象内存之前,把这个虚引用加入到与之关联的引用队列中。

程序能够通过推断引用队列中是否已经加入了虚引用,来知道对象是否将要被回收,这样我们就能够在对象被回收之前进行一些操作。

Reference

引用基类:这是一个抽象类。封装了关于引用的相关操作。如去除引用、比較、得到引用对象、推断引用地址是否相等。

ReferenceQueue

引用队列:在垃圾回收器回收对象之前,会将该引用加入到该队列。

SoftReference

软引用:假设内存空间不够用时,垃圾回收器就会回收该引用所引用到的内存对象。使用软引用能够实现内存敏感的快速缓存,软引用能够和引用队列联合使用。

WeakReference

弱引用:当垃圾回收器发现某个对象仅仅有弱引用时不管是否内存够用都会回收该对象,只是。因为垃圾回收器是一个优先级非常低的线程,因此不一定会非常快发现仅仅持有弱引用的对象。弱引用也能够和引用队列联合使用。

二、一个软(弱)引用的样例

以下我们来使用软引用读取一张图片,读出图片的宽和高,代码例如以下:

package 软引用;

import java.lang.ref.Reference;

/**
* 封装引用对象的基类
* @author CodeingSnail
*
* @param <T>
*/
public abstract class ReferenceObject<T>{ public Reference<T> ref; protected abstract T getInstance();
protected abstract Reference<T> getReference(T t); /*
* 获取引用对象及弱引用
*/
private T getRefrenceAndInstance(){
T t = getInstance();
getReference(t);
return t;
} /**
* 获取被引用的对象
* @return
*/
public T get(){
if(ref == null){
return getRefrenceAndInstance();
}
T t = ref.get();
if(t == null){
return getRefrenceAndInstance();
}
return t;
} /**
* 清空对象的引用。回收对象
*/
public void recycle() {
if(ref != null){
ref.clear();
ref = null;
}
}
}
import java.lang.ref.Reference;
import java.lang.ref.SoftReference; import javax.swing.ImageIcon; /**
* 引用图片资源的类
* @author Administrator
*
*/
public class ReferenceBitmap extends ReferenceObject<ImageIcon>{
String url;
public ReferenceBitmap(String url) {
this.url = url;
} @Override
protected Reference<ImageIcon> getReference(ImageIcon imageIcon) {
return new SoftReference<ImageIcon>(imageIcon);
} @Override
protected ImageIcon getInstance() {
return new ImageIcon(url);
} }
package 软引用;

public class Client {

	private ReferenceBitmap referenceBitmap;

	public static void main(String[] args) {
Client client = new Client();
client.referenceBitmap = new ReferenceBitmap("E:\\test.png");
System.out.println("图片的高度是:" + client.referenceBitmap.get().getIconHeight());
System.out.println("图片的宽度是:" + client.referenceBitmap.get().getIconWidth());
}
}

在上面样例中我们先定义了一个引用的抽象类,而且给子类提供两个回调方法用来创建图片对象和所须要的软引用(也能够是弱引用),在get()方法中获取对象的实例。事实上上面的样例是一个通用的方法。我们能够在getReference中定义我们须要的引用类型。假如我们如今已经非常明白,我们要的就是软引用,能够将代码简化例如以下:

public class Client {
SoftReference<ImageIcon> softRefrence;
private ReferenceBitmap referenceBitmap; public static void main(String[] args) {
Client client = new Client();
client.referenceBitmap = new ReferenceBitmap("E:\\test.png");
System.out.println("图片的高度是:" + client.referenceBitmap.get().getIconHeight());
System.out.println("图片的宽度是:" + client.referenceBitmap.get().getIconWidth()); //简化方法
client.softRefrence =
new SoftReference<ImageIcon>(new ImageIcon("E:\\test.png"));
System.out.println("图片的高度是:" + client.softRefrence.get().getIconHeight());
System.out.println("图片的宽度是:" + client.softRefrence.get().getIconWidth());
}
}

三、怎样配合引用队列使用

我们以下来分析一下java.util包下的WeakHashMap类,打开JDK后会发现对这个类有一个非常长的描写叙述。我们来一起看一下大概意思。
Hash table based implementation of the Map interface, with weak keys. An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded by the garbage collector, that is, made finalizable, finalized, and then reclaimed. When a key has been discarded its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.
这句话的大概意思是WeakHashMap的哈希表是基于Map接口的。当中key中保存的是value的一个弱引用。当系统回收了该key所相应的实际对象之后。WeakHashMap会自己主动删除该key相应的key-value对。
    /**
* The entries in this hash table extend WeakReference, using its main ref
* field as the key.
*/
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next; /**
* Creates new entry.
*/
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
} @SuppressWarnings("unchecked")
public K getKey() {
return (K) WeakHashMap.unmaskNull(get());
} public V getValue() {
return value;
} public V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
} public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<? ,?>)o;
K k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
V v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
} public int hashCode() {
K k = getKey();
V v = getValue();
return Objects.hashCode(k) ^ Objects.hashCode(v);
} public String toString() {
return getKey() + "=" + getValue();
}
}

WeakHashMap.Entry继承自WeakReference,在构造方法中能够看到直接将key交给WeakReference并通过ReferenceQueue关联。

    /**
* Expunges stale entries from the table.
*/
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length); Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {
Entry<K,V> next = p.next;
if (p == e) {
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}

WeakHashMap中有一个私有的expungeStaleEntries方法。会在大部分共同拥有方法中被调用,这种方法会将ReferenceQueue中全部失效的引用从Map中移除。WeakHashMap不会自己主动释放失效的引用,仅当包括了expungeStaleEntries方法被调用的时候才会释放。以下一个小样例来看一下WeakHashMap的使用:

	public static void main(String[] args) {
WeakHashMap<String, String> map = new WeakHashMap<String, String>();
map.put(new String("1"), "1");
map.put("2", "2");
String s = new String("3");
map.put(s, "3");
int i = 0;
while(map.size() > 0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Map Size: " + map.size());
System.out.println(map.get("1"));
System.out.println(map.get("2"));
System.out.println(map.get("3"));
if(i == 3) s = null;
System.gc();
i++;
}
}

输出结果:

Map Size: 3
1
2
3
Map Size: 2
null
2
3
Map Size: 2
null
2
3
Map Size: 2
null
2
3
Map Size: 1
null
2
null
Map Size: 1
null

上面的样例中。第一个key外部没有强引用,则仅仅打印了一次就被回收器回收,第三个key有外部的强引用。当我们将外部引用去掉后也被垃圾回收器回收。第二个key是被字符串常量池所引用,所以一直存在。

Java中的软(弱)引用的更多相关文章

  1. java中强,软,弱,虚引用 以及WeakHahMap

    java中强,软,弱,虚引用  以及WeakHahMap   一:强软引用: 参考:http://zhangjunhd.blog.51cto.com/113473/53092/进行分析   packa ...

  2. JAVA中的四种引用以及ReferenceQueue和WeakHashMap的使用示例

    简介: 本文主要介绍JAVA中的四种引用: StrongReference(强引用).SoftReferenc(软引用).WeakReferenc(弱引用).PhantomReference(虚引用) ...

  3. Java中的四种引用

    引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...

  4. JAVA中MESSAGEBOX,静态类直接引用

    原文:JAVA中MESSAGEBOX,静态类直接引用 package cisdi.mes.wrm.mcode.serviceImpl; import javax.persistence.Entity; ...

  5. Java中的基本类型和引用类型变量的区别

    Java中的基本类型和引用类型变量的区别   学了一年多,说实话你要我说这些东西我是真说不出来是啥意思     基本类型: 基本类型自然不用说了,它的值就是一个数字,一个字符或一个布尔值. 引用类型: ...

  6. java中的软引用,弱引用,虚引用

    http://zh.wikipedia.org/wiki/%E5%BC%B1%E5%BC%95%E7%94%A8 有些语言包含多种强度的弱引用.例如Java,在java.lang.ref[1]包中定义 ...

  7. java中的四种引用方式(强引用,软引用,弱引用,虚引用)

    java内存管理主要有内存分配和内存回收,都不需要程序员负责,垃圾回收的机制主要是看对象是否有引用指向该对象. java中对象的引用主要有四种:强引用,软引用,弱引用,虚引用. Java中提供这四种引 ...

  8. Java中的四种引用(强引用、软引用、弱引用、虚引用)

    以下内容摘自<深入理解Java虚拟机 JVM高级特性与最佳实践>第2版,强烈推荐没有看过的同学阅读,读完的感觉就是"原来学的都是些什么瘠薄东西(╯‵□′)╯︵┴─┴" ...

  9. java中的软,弱,虚引用介绍与特性分析

    java的弱,虚,软引用介绍 1.弱,虚,软引用的介绍 对于绝大部分的对象而言,在程序中是存在着一个引用变量引用该对象,这是常见的引用方式,也就是常说的 强引用,对于强引用引用的对象,系统JVM是不会 ...

随机推荐

  1. 【scrapy】使用方法概要(一)(转)

    [请初学者作为参考,不建议高手看这个浪费时间] 工作中经常会有这种需求,需要抓取互联网上的数据.笔者就经常遇到这种需求,一般情况下会临时写个抓取程序,但是每次遇到这种需求的时候,都几乎要重头写,特别是 ...

  2. MVC扩展生成CheckBoxList并水平排列

    本篇体验生成CheckBoxList的几个思路,扩展MVC的HtmlHelper生成CheckBoxList,并使之水平排开.     通过遍历从控制器方法拿到的Model集合 □ 思路 比如为一个用 ...

  3. centos安装sqlserver

    centos安装sqlserver 必要條件 您必须具有 RHEL 7.3 或 7.4 计算机至少 2 GB的内存. 若要在自己的计算机上安装 Red Hat Enterprise Linux,请转到 ...

  4. 转 如何在IOS设备中去掉屏幕上的status bar

    引入如何在IOS设备中去掉屏幕上的status bar,即:不显示设备上方的[网络.时间.电池??]条?操作方法一:在-info.list项目文件中,加上“Status bar is initiall ...

  5. sql把一个表的某几列的数据存到另一个表里

    一.如何用slq语句把一个表中的某几个字段的数据插入到另一个新表中,就要用下面这条slq语句:    insert into 表名1(字段1,字段2) select 字段1,字段2 from 表名2 ...

  6. Oracle约束的启用和停用

      关于Oracle的约束概念和基本操作,我已经在以前的<Constraint基础概念>.<Constraint的简单操作>两篇文章中有过比较详细的介绍了,但是对于如何停用和启 ...

  7. javax.imageio.IIOException: Can't create output stream! (生成验证码Servlet)

    在  web.xml里面加入 下面的代码: <servlet>         <servlet-name>validatecode</servlet-name> ...

  8. ubuntu下如何查看自己的外网IP

    1.1 安装使用curl命令实现      sudo apt-get install curl1.2 输入命令      curl ifconfig.me

  9. Jetty学习二:配置概览-怎么配置Jetty

    Jetty POJO配置 Jetty的核心组件是Plain Old Java Objects(POJOs):配置Jetty的大部分工作就是在Jetty POJOs上的初始化.装配和设置域的处理,你能通 ...

  10. 前端新手如何安装webstorm ,初步搭建react项目

    下载安装webstorm:配置成功: 配置成功后就可以开启webstorm项目了.(存微信收藏..) 1:在webstorm下配置node环境: 2:完成之后: React官方脚手架地址: https ...