Javadoc 8 for PhantomReference
states:
Phantom references are most often used for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.
So I tried creating a thread that is calling the close() method of a Test Object that is eligible for garbage collection. The run() tries to get all Test Objects pre-mortem.
Actually the retrieved Test Objects are all null. The expected behavior is, that the Test Objects are retrieved and the closemethod is called.
No matter how many Test Objects you create there is not a single Test Object that could be caught pre-mortem (You have to increase the timeouts and call GC multiple times).
What am I doing wrong? Is this a Java Bug?
Runnable Test Code:
I tried to create a Minimal, Complete, and Verifiable example, but it's still quite long. I use java version "1.8.0_121" 32-bit on Windows 7 64-bit.
public class TestPhantomReference {
public static void main(String[] args) throws InterruptedException {
// Create AutoClose Thread and start it
AutoCloseThread thread = new AutoCloseThread();
thread.start();
// Add 10 Test Objects to the AutoClose Thread
// Test Objects are directly eligible for GC
for (int i = 0; i < 2; i++) {
thread.addObject(new Test());
}
// Sleep 1 Second, run GC, sleep 1 Second, interrupt AutoCLose Thread
Thread.sleep(1000);
System.out.println("System.gc()");
System.gc();
Thread.sleep(1000);
thread.interrupt();
}
public static class Test {
public void close() {
System.out.println("close()");
}
}
public static class AutoCloseThread extends Thread {
private ReferenceQueue<Test> mReferenceQueue = new ReferenceQueue<>();
private Stack<PhantomReference<Test>> mPhantomStack = new Stack<>();
public void addObject(Test pTest) {
// Create PhantomReference for Test Object with Reference Queue, add Reference to Stack
mPhantomStack.push(new PhantomReference<Test>(pTest, mReferenceQueue));
}
#Override
public void run() {
try {
while (true) {
// Get PhantomReference from ReferenceQueue and get the Test Object inside
Test testObj = mReferenceQueue.remove().get();
if (null != testObj) {
System.out.println("Test Obj call close()");
testObj.close();
} else {
System.out.println("Test Obj is null");
}
}
} catch (InterruptedException e) {
System.out.println("Thread Interrupted");
}
}
}
}
Expected Output:
System.gc()
Test Obj call close()
close()
Test Obj call close()
close()
Thread Interrupted
Actual Output:
System.gc()
Test Obj is null
Test Obj is null
Thread Interrupted
This is by design. Unlike finalize(), which makes an object reachable again, objects referable by a Reference object only can not be made reachable again. So when you are going to manage a resource through it, you have to store the necessary information into another object. It’s not unusual, to use the Reference object itself for it.
Consider the following modifications to your test program:
public class TestPhantomReference {
public static void main(String[] args) throws InterruptedException {
// create two Test Objects without closing them
for (int i = 0; i < 2; i++) {
new Test(i);
}
// create two Test Objects with proper resource management
try(Test t2=new Test(2); Test t3=new Test(3)) {
System.out.println("using Test 2 and 3");
}
// Sleep 1 Second, run GC, sleep 1 Second
Thread.sleep(1000);
System.out.println("System.gc()");
System.gc();
Thread.sleep(1000);
}
static class TestResource extends PhantomReference<Test> {
private int id;
private TestResource(int id, Test referent, ReferenceQueue<Test> queue) {
super(referent, queue);
this.id = id;
}
private void close() {
System.out.println("closed "+id);
}
}
public static class Test implements AutoCloseable {
static AutoCloseThread thread = new AutoCloseThread();
static { thread.start(); }
private final TestResource resource;
Test(int id) {
resource = thread.addObject(this, id);
}
public void close() {
resource.close();
thread.remove(resource);
}
}
public static class AutoCloseThread extends Thread {
private ReferenceQueue<Test> mReferenceQueue = new ReferenceQueue<>();
private Set<TestResource> mPhantomStack = new HashSet<>();
public AutoCloseThread() {
setDaemon(true);
}
TestResource addObject(Test pTest, int id) {
final TestResource rs = new TestResource(id, pTest, mReferenceQueue);
mPhantomStack.add(rs);
return rs;
}
void remove(TestResource rs) {
mPhantomStack.remove(rs);
}
#Override
public void run() {
try {
while (true) {
TestResource rs = (TestResource)mReferenceQueue.remove();
System.out.println(rs.id+" not properly closed, doing it now");
mPhantomStack.remove(rs);
rs.close();
}
} catch (InterruptedException e) {
System.out.println("Thread Interrupted");
}
}
}
}
which will print:
using Test 2 and 3
closed 3
closed 2
System.gc()
0 not properly closed, doing it now
closed 0
1 not properly closed, doing it now
closed 1
showing how using the correct idiom ensures that resources are closed timely and, unlike finalize(), the object can opt out the post-mortem cleanup which makes using the correct idiom even more efficient, as in that case, no additional GC cycle is needed to reclaim the object after finalization.
get() method on phantom references always return null.
At the moment phantom reference is enqueued object it was referencing is already collected by GC. You need to store data required to clean up in separate object (e.g. you can subclass PhantomReference).
Here you can find example code and more elaborate description about using PhantomReferences.
Unlike finalizer, phantom reference cannot resurrect unreachable object. This is its main advantage, though cost is more complicated supporting code.
Related
I have a utility class which starts a long running background thread. The utility class is initialized in main class. But utility class object is getting garbage collected. How can i prevent that. Here is my class structure.
public class Main {
public static void main(String[] args) throws Exception {
Utility u = new Utility();
u.startTask(); //This is not referenced after this and hence getting gc'ed
.....
....
api.addMessageCreateListener(event -> {
/////continuously running
}
}
}
What i want is to prevent Utility object from getting garbage collected.
I assume the Method Utility#startTask() starts Threads on its own, otherwise this would be a blocking call and the main-Method would not end before startTask returned.
However this should not stop you from implementing the Runnable Interface in Utility itself. As long as the Utility runs in its own Thread, you do not need to worry about the enclosing method returning. Since the Tread is still running, the Instance will not be collected.
public class Threading {
public static void main(String[] args) {
Utility utility = new Threading().new Utility();
Future utilFuture = Executors.newSingleThreadExecutor().submit(utility);
System.out.println("end main");
}
public class Utility implements Runnable {
#Override
public void run() {
System.out.println("Start Utility");
for(int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
System.out.println("foo: " + i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
}
}
}
}
Note: In your case you might not need the Future, but it is an extremely useful tool to interrupt the Execution if needed.
I have a method, disconnectUser() which among other things, assigns null to an object userSession at the end of execution. However, a hypothetical arose as I was coming up with the logic, where say userSession has a running method and it is assigned a null reference while it is still executing; how does the JVM deal with such a situation?
FWIW here are some code snippets for context:
public class A {
UserSession userSession;
/* Skipped irrelevant code
*-------------------------------
*/
private void disconnectUser(){
//Runs an endless while-loop (it's for demonstration's sake)
userSession.runEndlessLoop();
userSession = null;
}
}
ADDENDUM:
Here's the implementation for runEndlessLoop
public void runEndlessLoop(){
Executors.newSingleThreadExecutor().execute(() -> while(true){});
}
userSession is a reference to an object. You "assign" null to this reference, not to an object. So you are changing this reference. It doesn't change the object userSession formerly referenced / pointed to.
Also see: Can unreferenced objects still run if the garbage collector hasn't deleted them?
Let me try to add this: If the method of this object is running in the same thread as the rest of your program, the reference would be changed after this method finishes, so the problem doesn't even come up.
If, in contrast, this object acts in a different thread, well... i just tested it:
public class UnreferencedTest {
public static void main(String[] args) {
UnreferencedTest u = new UnreferencedTest();
u.createObject();
}
private void createObject() {
Unreferenced obj = new Unreferenced();
Thread t = new Thread(obj);//create new thread
t.start();
obj = null; //remove only reference to object
System.gc(); //ask GC to clean up
try {
Thread.sleep(10000); //wait a bit longer than other thread
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class Unreferenced implements Runnable {
#Override
public void run() {
try {
Thread.sleep(5000);
areYouStillHere();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void areYouStillHere() {
System.out.println("I'm still here!");
}
}
}
... and even "asked" the GC to clean up unreferenced objects. (no guarantee it does!) It's only waiting for 5 seconds, but still runs.
Hope that helps!
Here is my code
public class FinalizableObject {
#Override
protected void finalize() throws Throwable {
System.out.println("finalize() invoked for " + this);
super.finalize();
}
}
public class Main {
private static void test() throws InterruptedException {
ReferenceQueue<FinalizableObject> rq = new ReferenceQueue<FinalizableObject>();
FinalizableObject obj = new FinalizableObject();
PhantomReference<FinalizableObject> pr1 = new PhantomReference<FinalizableObject>(obj, rq);
obj = null;
System.gc();
Reference<? extends Object> ref = rq.remove();
System.out.print("remove " + ref + " from reference queue\n");
}
public static void main(String[] args) {
try {
test();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
It's very strange, rq.remove() will be blocked forever. Why my finalizable object's phantom reference can not be put into reference queue? Has it been GC collected?
The problem is with your non-trivial finalize() method. In default implementation (in class Object) this method is actually empty. When its implementation isn't empty, then it is not guaranteed that object will be instantly collected after invoking finalize().
If you will modify your program in such style:
for (int i = 0; i < 1000; i++)
System.gc();
i.e. you will call GC more then one times - it could lead to the rq object be fully collected (test on my machine).
Also, I suggest you following links to explore:
Java: PhantomReference, ReferenceQueue and finalize
Discovering Objects with Non-trivial Finalizers
The Secret Life Of The Finalizer: page 2 of 2
UPD: Another way: you have to hold in mind, that non-trivial finalize() methods is invoked by special Finalizer-Thread, which also have to be collected. So, for full pr collecting you can do such things:
a) create flag inside Main method:
public static volatile boolean flag;
b) set flag in finalize() method:
#Override
protected void finalize() throws Throwable {
System.out.println("finalize() invoked for " + this);
super.finalize();
Main.flag = true;
}
c) check flag for true and then call gc() again:
System.gc();
while (!flag) Thread.sleep(10);
System.gc();
I'm working on a multithreaded Java project where I would like to have objects that prevent their methods from being called from any thread for some period of time. Ideally, those method calls would not be thrown out, but simply queued up until the cooldown from the previous method has completed. Here's a simple example of a class with that kind of functionality:
public class A {
private synchronized void cooldown(long ms) {
long finishTime = ms + System.currentTimeMillis();
while (System.currentTimeMillis() < finishTime);
}
public synchronized void foo() {
// foo's code
cooldown(1000);
}
public synchronized void bar() {
// bar's code
cooldown(2000);
}
}
This works, but I'm expecting to have quite a few of the above objects and I feel like the loop inside of cooldown() is wasteful. I'd love to use a construct like Thread.sleep(), but in this case, that would have the undesirable effects of forcing the calling thread to sleep and not preventing any other thread from making method calls on A. Any suggestions?
EDIT:
To clarify, given the following implementation:
public synchronized void foo() {
System.out.println("foo");
cooldown(1000);
}
public synchronized void bar() {
System.out.println("bar");
cooldown(2000);
}
public static void main(String[] args) {
final A a = new A();
new Thread(new Runnable() {
public void run() {
a.foo();
}
}).start();
System.out.println("foobar");
new Thread(new Runnable() {
public void run() {
a.bar();
}
}).start();
}
I would like foo and foobar to print instantly (order doesn't matter), followed by bar a second later. If cooldown() just called Thread.currentThread().sleep(ms) instead of the current implementation, then foo would print instantly, followed by foobar and bar a second later.
I'd love to use a construct like Thread.sleep(), but in this case, that would have the undesirable effects of forcing the calling thread to sleep and not preventing any other thread from making method calls on A. Any suggestions?
I don't see the difference between calling Thread.sleep() versus your spin loop aside from the fact that the spin loop wastes CPU. If you are inside cooldown(...) then that instance of A is synchronized.
If you mean that you have other methods that are synchronized and you don't want the thread that is cooling down to be holding the lock then you can use this.wait(...) which will release the lock during the sleep. Of course is someone is calling notify(...) this won't work.
private synchronized void cooldown(long ms) {
try {
long waitUntilMillis = System.currentTimeMillis() + ms;
long waitTimeMillis = ms;
do {
this.wait(waitTimeMillis);
// we need this dance/loop because of spurious wakeups, thanks #loki
waitTimeMillis = waitUntilMillis - System.currentTimeMillis();
} while (waitTimeMillis > 0);
} catch (InterruptedException e) {
Thread.currentThread.interrupt();
}
}
The right thing to do is to not have synchronized methods and only synchronize when you specifically need to. Then you can cooldown easily without holding a lock.
private void cooldown(long ms) {
try {
this.sleep(ms);
} catch (InterruptedException e) {
Thread.currentThread.interrupt();
}
}
public void foo() {
synchronized (this) {
// foo's code
}
cooldown(1000);
}
You have following options:
Thread.sleep() should work fine if called inside synchronized method. All other threads would be prevented and your thread will hold lock and wait.
Use timed wait/notify in a synchronized block. That should also do the job.
EDIT:
See the below code
public class A {
final volatile Object lck = new Object();
volatile boolean waitStatus = true;
private void cooldown(long ms) {
synchronized(lck){
long startTime = System.currentTimeMillis();
//Do thread need to wait
if(waitStatus){
while(System.currentTimeMillis()-startTime < ms)
lck.wait(gapTime);
//Wait over no other thread will wait
waitStatus = false;
}
}
}
public void foo() {
// foo's code
cooldown(1000);
}
public void bar() {
// bar's code
cooldown(2000);
}
}
You are very close already ... minor change ...
private synchronized void cooldown(long ms) throws InterruptedException {
Thead.sleep(ms);
}
Alternatively, you could handle the InterruptedException in the cooldown method itself.
Also, note that your code could actually execute foo, bar, and foobar in any order. The cooldown will slow down the foo or the bar (depending on which gets executed first).
I'd love to use a construct like Thread.sleep(), but in this case,
that would have the undesirable effects of forcing the calling thread
to sleep and not preventing any other thread from making method calls
on A.
Your approach does what you want. Other threads ARE prevented from making method calls on A (if you have synchronized the methods - which you have).
I am creating an interface for executing methods concurrently, while abstracting away the synchronization details (To swap for a distributed implementation when needed). I've created a single jvm implementation that allows Strings to be used as the mutex by storing them in a map to ensure one reference is used, even if Strings of different references are passed in. The concurrency seems to work fine, however I was surprised to see that the test was showing the reference count is never decreasing. I assumed using WeakValues() would be enough to prevent memory leaks, but it seems that is not the case. Can anyone point out what could be causing this leak?
public class SynchronousMethodExecutorSynchronizedImpl implements ISynchronousMethodExecutor {
// mutex map to provide string references
final Map<String, String> mutexMap = new MapMaker()
.weakValues()
.makeComputingMap(
new Function<String, String>() {
#Override
public String apply(String id) {
return id;
}
});
#Override
public Object doSynchronousMethod(String domain, String id, ISynchronousMethod synchronousMethod) {
synchronized(mutexMap.get(domain + "." + id))
{
return synchronousMethod.execute();
}
}
}
Here is the test that is failing at the very last assertion:
public class SynchronousMethodExecutorSynchronizedImplTest extends TestCase {
int counter;
SynchronousMethodExecutorSynchronizedImpl methodExecutor;
#Override
public void before() throws Exception {
super.before();
methodExecutor = new SynchronousMethodExecutorSynchronizedImpl();
}
#Test
public void concurrentExecute() throws InterruptedException {
assertEquals(0, counter);
for(int i=0; i<1000; i++)
getConcurrentExecutorThread().start();
// wait for threads to complete
Thread.sleep(1000);
assertEquals(1, methodExecutor.mutexMap.size());
try
{
final List<long[]> infiniteList = new LinkedList<long[]>();
for(long i = Long.MIN_VALUE; i < Long.MAX_VALUE; i++)
infiniteList.add(new long[102400]);
fail("An OutOfMemoryError should be thrown");
}
catch(OutOfMemoryError e)
{
}
assertEquals(2000, counter);
assertEquals(0, methodExecutor.mutexMap.size());
}
// synchronous method
private ISynchronousMethod method = new ISynchronousMethod() {
#Override
public Object execute() {
counter++;
return null;
}
};
/**
* Executes a line of code.
*
* #return Thread
*/
private Thread getConcurrentExecutorThread() {
return new Thread() {
#Override
public void run() {
methodExecutor.doSynchronousMethod("TEST", "1", method);
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
}
methodExecutor.doSynchronousMethod("TEST", new String("1"), method);
}
};
}
}
This last assertion is what breaks the test:
assertEquals(0, methodExecutor.mutexMap.size());
You're storing the exact same String object as both the key and the value. The key is a strong reference to the object, and as long as a strong reference to it exists, the weak reference to it is meaningless. The definition of weakly reachable (here) states that:
An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference.
By the way, even with this corrected I don't think you can assume that the map will always be empty at the end. It will probably be close to empty, but I think that's all that can be said about it.
Weak references will only be collected when the JVM absolutely needs more memory.