引用的类型主要关注的是该引用如何与GC交互。
1.Strong References
java中常见的引用类型:
StringBuffer buf = new StringBuffer();
这里buf就是一个强引用。如果一个对象在一条强引用链上可达,那么它不适合GC,也不会被回收。
2.Weak References
弱引用,是一种较弱的引用,它不会阻止GC回收只被弱引用引用的对象。
当一个对象最强只被弱引用引用时,那么在下个GC周期,它可以被回收.
你可以使用如下的方式构建一个弱引用:
WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget);
在其他地方你可以使用如下的代码来获取原始对象:
weakWidget.get()
但是你可能会得到一个NULL值。
使用到弱引用的常见类是:
ThreadLocal类:
java.util.WeakHashMap
3.Soft References
软引用,与弱引用类似,弱引用在下一个GC周期就会被回收,但是软引用一般会坚持更久.
更常见的,软引用,只要在内存够用的情况下就会一直存在.
那么它非常适合实现缓存.
下图是jdk中的继承关系图,可以看见很多跟缓存相关.
更多可以参考Google guava:
com.google.common.collect.MapMakerInternalMap
4.Phantom References
幻象引用,一种更弱的引用,最弱的,它的get()方法总是返回NULL.
它一般用于在对象GC时得到一个通知,通知你可以做一些别的事情,
在apache的commons-fileupload 和commons-io中很巧妙的使用了这个类,来实现上传时临时文件的清除.
在commons-fileupload中每个文件都指定了一个文件清除的跟踪器.
org.apache.commons.fileupload.disk.DiskFileItemFactory.fileCleaningTracker
而commons-io中实现,最重要的在:Reaper线程的run方法中.(删除了部分代码.)
package org.apache.commons.io;
/**
* Keeps track of files awaiting deletion, and deletes them when an associated
* marker object is reclaimed by the garbage collector.
* <p>
* This utility creates a background thread to handle file deletion.
* Each file to be deleted is registered with a handler object.
* When the handler object is garbage collected, the file is deleted.
* <p>
* In an environment with multiple class loaders (a servlet container, for
* example), you should consider stopping the background thread if it is no
* longer needed. This is done by invoking the method
*/
public class FileCleaningTracker {
// Note: fields are package protected to allow use by test cases
/**
* Queue of <code>Tracker</code> instances being watched.
*/
ReferenceQueue<Object> q = new ReferenceQueue<Object>();
/**
* Collection of <code>Tracker</code> instances in existence.
*/
final Collection<Tracker> trackers = Collections.synchronizedSet(new HashSet<Tracker>()); // synchronized
/**
* Whether to terminate the thread when the tracking is complete.
*/
volatile boolean exitWhenFinished = false;
/**
* The thread that will clean up registered files.
*/
Thread reaper;
/**
* Track the specified file, using the provided marker, deleting the file
* when the marker instance is garbage collected.
* The speified deletion strategy is used.
*
* @param path the full path to the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @param deleteStrategy the strategy to delete the file, null means normal
* @throws NullPointerException if the path is null
*/
public void track(final String path, final Object marker, final FileDeleteStrategy deleteStrategy) {
if (path == null) {
throw new NullPointerException("The path must not be null");
}
addTracker(path, marker, deleteStrategy);
}
/**
* Adds a tracker to the list of trackers.
*
* @param path the full path to the file to be tracked, not null
* @param marker the marker object used to track the file, not null
* @param deleteStrategy the strategy to delete the file, null means normal
*/
private synchronized void addTracker(final String path, final Object marker, final FileDeleteStrategy
deleteStrategy) {
// synchronized block protects reaper
if (exitWhenFinished) {
throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called");
}
if (reaper == null) {
reaper = new Reaper();
reaper.start();
}
trackers.add(new Tracker(path, deleteStrategy, marker, q));
}
//-----------------------------------------------------------------------
/**
* The reaper thread.
*/
private final class Reaper extends Thread {
/** Construct a new Reaper */
Reaper() {
super("File Reaper");
setPriority(Thread.MAX_PRIORITY);
setDaemon(true);
}
/**
* Run the reaper thread that will delete files as their associated
* marker objects are reclaimed by the garbage collector.
*/
@Override
public void run() {
// thread exits when exitWhenFinished is true and there are no more tracked objects
while (exitWhenFinished == false || trackers.size() > 0) {
try {
// Wait for a tracker to remove.
final Tracker tracker = (Tracker) q.remove(); // cannot return null
trackers.remove(tracker);
if (!tracker.delete()) {
deleteFailures.add(tracker.getPath());
}
tracker.clear();
} catch (final InterruptedException e) {
continue;
}
}
}
}
//-----------------------------------------------------------------------
/**
* Inner class which acts as the reference for a file pending deletion.
*/
private static final class Tracker extends PhantomReference<Object> {
/**
* The full path to the file being tracked.
*/
private final String path;
/**
* The strategy for deleting files.
*/
private final FileDeleteStrategy deleteStrategy;
/**
* Constructs an instance of this class from the supplied parameters.
*
* @param path the full path to the file to be tracked, not null
* @param deleteStrategy the strategy to delete the file, null means normal
* @param marker the marker object used to track the file, not null
* @param queue the queue on to which the tracker will be pushed, not null
*/
Tracker(final String path, final FileDeleteStrategy deleteStrategy, final Object marker,
final ReferenceQueue<? super Object> queue) {
super(marker, queue);
this.path = path;
this.deleteStrategy = deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy;
}
/**
* Deletes the file associated with this tracker instance.
*
* @return {@code true} if the file was deleted successfully;
* {@code false} otherwise.
*/
public boolean delete() {
return deleteStrategy.deleteQuietly(new File(path));
}
}
}