Here is the code before my question. First there is an interface:
public interface SomeAction {
public void doAction();
}
Then there are two classes:
public class SomeSubscriber {
public static int Count;
public SomeSubscriber(SomePublisher publisher) {
publisher.subscribe(this);
}
public SomeAction getAction() {
final SomeSubscriber me = this;
class Action implements SomeAction {
@Override
public void doAction() {
me.doSomething();
}
}
return new Action();
}
// specify what to do just before it is garbage collected
@Override
protected void finalize() throws Throwable {
SomeSubscriber.Count++;
System.out.format("SomeSubscriber count: %s %n", someSubscriber.Count);
}
private void doSomething() {
// TODO: something
}
}
The second class:
public class SomePublisher {
private List<SomeAction> actions = new ArrayList<SomeAction>();
public void subscribe(SomeSubscriber subscriber) {
actions.add(subscriber.getAction());
}
}
This is the code that is used to test the two classes:
public class Test {
//output: "the answer is: 0" for the 1st run after compilation and running attemptCleanUp() first, stays 0 upon repeat run
public static void main (String args []) {
System.out. println("am in main()");
SomePublisher publisher = new SomePublisher();
for (int i = 0; i < 10; i++) {
SomeSubscriber subscriber = new SomeSubscriber(publisher);
subscriber = null;
}
attemptCleanUp();
}
//output: "the answer is: 0" for the 1st run after compilation and running attemptCleanUp() first, rising to 10, 20, 30 ...upon repeat run
public static void answerIsNot0() {
System.out. println("am in answerIsNot0()");
SomePublisher publisher = new SomePublisher();
for (int i = 0; i < 10; i++) {
SomeSubscriber subscriber = new SomeSubscriber(publisher);
subscriber = null;
}
attemptCleanUp();
}
private static void attemptCleanUp() {
threadMessage("Before the gc attempt, the answer is: " + SomeSubscriber.Count);
System.gc();
System.runFinalization();
threadMessage("After the gc attempt, the answer is: " + SomeSubscriber.Count);
}
private static void threadMessage(String message) {
String threadName =
Thread.currentThread().getName();
System.out.format("%s: %s%n",
threadName,
message);
}
}
The printout from main() shows SomeSubscriber.Count value of 1 to 10, while the final line produced The answer is: 0
,like below:
am in main()
main: Before the gc attempt, the answer is: 0
SomeSubscriber count: 1
SomeSubscriber count: 2
SomeSubscriber count: 3
SomeSubscriber count: 4
SomeSubscriber count: 5
SomeSubscriber count: 6
SomeSubscriber count: 7
SomeSubscriber count: 8
SomeSubscriber count: 9
SomeSubscriber count: 10
main: After the gc attempt, the answer is: 0
whereas for answerIsNot0(), the number inside The answer is: <num>
always matches the last number in the SomeSubscriber count:
series.
My questions are: First, do the non-zero values show that the garbage collection indeed happened 10 times? This contradicts with the notion that the 10 subscriber
s are all still referenced by the instances of the local class Action
in the publisher
instance, and therefore not subjected to garbage-collection. Secondly, how has the value of SomeSubscriber.Count changed at the final statement in main (String args []) {} method, but not at the answerIsNot0() method? In another word, why does the same code produce different effect on SomeSubscriber.Count
when placed in main() as opposed to when placed inside answerIsNot0()?