我正在尝试创建一个后台线程,以给定的时间间隔更新Runnable。
它也不应该阻止“父母”收集垃圾。
我的问题如下。我的WeakReference似乎是一个“强大的”引用,它不会阻止我的线程形式访问我应该为gc提供的runnable。
为什么我的Weakreference会阻止gc?
以下是我的全面实施
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
public final class WeakIntervalUpdater {
private final long updateFrequencyMs;
private final WeakReference updateObject;
private Thread runningThread;
/**
* Will keep a thread running fireing the updaterunnable every updateFrequencyMs.
*
* the updateRunnable is first fired after updateFrequencyMs ms after startUpdating() is called
*
* This thread will require calls to be made to stopUpdating() or that the
* updateRunnable is garbage collected to stop updateing and be eligable for
* garbage collection.
*
* This class maintains only a weak reference to the updateRunnablein order.
*
*
* @param updateFrequencyMs number of ms between each update
* @param updateRunnable the update runnable
*/
public WeakIntervalUpdater(long updateFrequencyMs, Runnable updateRunnable) {
this.updateFrequencyMs = updateFrequencyMs;
this.updateObject = new WeakReference(updateRunnable);
}
public void startUpdating() {
if (runningThread != null) {
if (runningThread.isAlive()) {
return;
}
runningThread.interrupt();
runningThread = new Thread(createThreadRunnable());
} else {
runningThread = new Thread(createThreadRunnable());
}
runningThread.setDaemon(true);
runningThread.start();
}
public void stopUpdating() {
if (runningThread != null) {
runningThread.interrupt();
runningThread = null;
}
}
Runnable createThreadRunnable() {
return new ThreadRunnable();
}
private class ThreadRunnable implements Runnable {
public void run() {
Object object;
while ((object = updateObject.get()) != null) {
System.out.println("object is now: " + object);
try {
Thread.sleep(updateFrequencyMs);
} catch (InterruptedException ex) {
System.out.println("Thread interrupted, killing thread");
return;
}
((Runnable) object).run();
object = null;
}
System.out.println("lost object reference: killing thread");
}
}
private static void printTestHelp() {
System.out.println("\n\n\n\n---------------------");
System.out.println("Commands:");
System.out.println("c : create an updater with a reference to an updateRunnable");
System.out.println("r : release reference to updateRunnable");
System.out.println("gc: run garbagecollection");
System.out.println("s : stop updater");
System.out.println("i : print object references");
System.out.println("q : quit program");
System.out.println("\nPlease enter your command");
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
WeakIntervalUpdater updater = null;
Runnable myUpdateRunnable = null;
printTestHelp();
while (!(line = br.readLine()).equals("q")) {
if (line.equals("c")) {
if (updater != null) {
updater.stopUpdating();
System.out.println("\tUpdater stopped");
}
myUpdateRunnable = new UpdateTesterRunnable();
updater = new WeakIntervalUpdater(1000, myUpdateRunnable);
updater.startUpdating();
System.out.println("\tcreated updater! updateing every 1000 ms");
} else if (line.equals("r")) {
//updater = null;
myUpdateRunnable = null;
System.out.println("\tDropped refrence to updater!");
System.out.println("\tupdateRunnable=" + myUpdateRunnable);
} else if (line.equals("gc")) {
System.gc();
Runtime.getRuntime().runFinalization();
System.out.println("\tGarbage collection running!");
} else if (line.equals("s")) {
if (updater != null) {
updater.stopUpdating();
System.out.println("\tUpdater stopped");
} else {
System.out.println("\tNo updater running");
}
} else if (line.equals("i")) {
System.out.println("\tupdater = " + updater);
System.out.println("\tupdateRunnable = " + myUpdateRunnable);
} else {
printTestHelp();
}
}
System.out.println("Goodbye");
}
private static class UpdateTesterRunnable implements Runnable {
public void run() {
System.out.println("\t\t\t(updating)");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize");
}
}
}
答案 0 :(得分:1)
除了使ThreadRunnable静态之外,还需要在 Thread.sleep()之前将对象设置为null。除非清除该引用,否则垃圾收集器无法回收该对象。 只需将 Thread.sleep()代码移到 object = null; 分配下面,这样就可以给垃圾收集器一个机会。
public void run() {
Object object;
while ((object = updateObject.get()) != null) {
System.out.println("object is now: " + object);
((Runnable) object).run();
object = null;
try {
Thread.sleep(updateFrequencyMs);
} catch (InterruptedException ex) {
System.out.println("Thread interrupted, killing thread");
return;
}
}
System.out.println("lost object reference: killing thread");
}
答案 1 :(得分:0)
不确定是否是原因,但ThreadRunnable
是非静态内部类,这会在其生成的构造函数中传递对包含类的引用。您可以尝试将其设置为静态内部类,并在构造函数中手动传递必要参数,如下所示(未经测试):
static class ThreadRunnable implements Runnable {
private WeakReference updateObject;
ThreadRunnable(WeakReference updateObject) {
this.updateObject = updateObject;
}
public void run() { ... }
}
答案 2 :(得分:0)
我建议你不要指望对你的main中的局部变量进行归零以利用runnable到gc。你能否将部分或全部if-then块拆分为自己的方法,并使runnable只能在其中一种方法中使用局部变量。