If you discard a reference to a Future, will it still run? - java

In my method, I have to call another method (AnotherMethod) that returns a future.
eg.
private static void myMethod() {
Future<MyObj> mjObj = AnotherMethod();
return;
}
I don't actually care about the value returned by AnotherMethod (eg. the value of myObj), but I do want AnotherMethod to run fully.
If I discard the reference to the future (as in the above example), will AnotherMethod still finish running?
I understand it won't finish before returning from myMethod, but will it still complete at some point even though there's no reference to myObj anymore?

First of all, AnotherMethod always will be performed from the start to the end because you call it. As for concurrency, if AnotherMethod starts a Thread or submits task to an executor then this concurrent execution will not be interrupted. Garbage collector does not interrupt threads because they are GC roots - top level objects in JVM.

Related

CompletableFuture Chain uncompleted -> Garbage Collector?

if i have one (or more) CompletableFuture not started yet, and on that method(s) a few thenApplyAsync(), anyOf()-methods.
Will the Garbage Collector remove all of that?
If there is a join()/get() at the end of that chain -> same question: Will the Garbage Collector remove all of that?
Maybe we need more information about that context of the join().
That join is in a Thread the last command, and there are no side-effects.
So is in that case the Thread still active? - Java Thread Garbage collected or not
Anyway is that a good idea, to push a poisen-pill down the chain, if im sure (maybe in a try-catch-finally), that i will not start that Completable-chain, or is that not necessary?
The question is because of something like that? (https://bugs.openjdk.java.net/browse/JDK-8160402)
Some related question to it: When is the Thread-Executor signaled to shedule a new task? I think, when the CompletableFuture goes to the next chained CompletableFuture?. So i must only carry on memory-leaks and not thread-leaks?
Edit: What i mean with a not started CompletableFuture?
i mean a var notStartedCompletableFuture = new CompletableFuture<Object>(); instead of a CompletableFuture.supplyAsync(....);
I can start the notStartedCompletableFuture in that way:
notStartedCompletableFuture.complete(new Object); later in the program-flow or from another thread.
Edit 2: A more detailed Example:
AtomicReference<CompletableFuture<Object>> outsideReference=new AtomicReference<>();
final var myOuterThread = new Thread(() ->
{
final var A = new CompletableFuture<Object>();
final var B = new CompletableFuture<Object>();
final var C = A.thenApplyAsync((element) -> new Object());
final var D = CompletableFuture.anyOf(A, C);
A.complete(new Object());
// throw new RuntimeException();
//outsideReference.set(B);
----->B.complete(new Object());<------ Edit: this shouldn't be here, i remove it in my next iteration
D.join();
});
myOuterThread.start();
//myOutherThread variable is nowhere else referenced, it's sayed so a local variable, to point on my text on it^^
So in the normal case here in my example i don't have a outside
reference. The CompletableFutures in the thread have never a chance
getting completed. Normally the GC can safely erase both the thread
and and the content in there, the CompetableFutures. But i don't
think so, that this would happen?
If I abbord this by throwing an exception -> the join() is never
reached, then i think all would be erased by the GC?
If I give one of the CompletableFutures to the outside by that AtomicReference, there then could be an chance to unblock the join(), There should be no GC here, until the unblock happens. BUT! the waiting myOuterThread on that join() doesen't have to to there anything more after the join(). So it could be an optimization erasing that Thread, before someone from outside completes B. But I think this would be also not happen?!
One more question here, how I can proof that behavior, if threads are blocked by waiting on a join() or are returned to a Thread-Pool?, where the Thread also "blocks"?
You seem to be struggling with different ways that CompletableFuture might leak, depending on how you created it. But it doesn't matter how, where, when or why it was created. The only thing that matters is whether or not it is still reachable.
Will the Garbage Collector remove all of that?
There are two places where we would expect there to be references to a CompletableFuture:
In the Runnable (or whatever) that would complete the future.
In any other code that would (at some point) attempt to get the eventual value from the future.
If you have a call thenApplyAsync() or anyOf() then the reference Runnable is in the arguments to that call. If the call can still happen, then the reference to the Runnable must still be reachable.
In your example:
var notStartedCompletableFuture = new CompletableFuture<Object>();
if the variable notStartedCompletableFuture is still accessible by some code that is still executing, then that CompletableFuture is reachable and won't be garbage collected.
On the other hand, if notStartedCompletableFuture is no longer accessible, and if the future is no longer reachable by some other path, then it won't be reachable at all ... and will be a candidate for garbage collection.
If there is a join() / get() at the end of that chain -> same question: Will the Garbage Collector remove all of that?
That makes no difference. It is all based on reachability. (The only wrinkle is that a thread that is currently alive1 is always reachable, irrespective of any other references to its Thread object. The same applies to its Runnable, and other objects reachable from the Runnable.)
But it is worth noting that if you call join() or get() on a thread / future that never terminates / completes, you will block the current thread, potentially for ever. And that is as bad as a thread leak.
1 - A thread is "alive" from when it is started to when it terminates.
When is the Thread-Executor signaled to schedule a new task?
It depends what you mean by "schedule". If you mean, when is the task submitted, the answer is when submit is called. If you mean, when is it actually run ... well it goes into the queue, and it runs when it gets to the head of the queue and a worker thread is free to execute it.
In the case of thenApplyAsync() and all_of(), the tasks are submitted (i.e. the submit(...) call occurs) when the respective method call occurs. So for example if thenApplyAsync is being called on the result of a previous call, then that call must return first.
This is all a consequence of the basic properties of Java expression evaluation ... applied to the expression that you are using to construct the chain of stages.
In general you don't need try / finally or try with resources to clean up potential memory leaks.
All you need to do is to make sure that you don't keep references to the various futures, stages, etc in variables, data structures, etc that will remain accessible / reachable beyond the lifetime of your computation. If you do that ... those references are liable to be the source of the leaks.
Thread leaks should not be your concern. If your code is not creating threads explicitly, they are being managed by the executor service / pool.
If a thread calls join() or get() on a CompletableFuture that will never be completed, it will remain blocked forever (except if it gets interrupted), holding a reference to that future.
If that future is the root of a chain of descendant futures (+ tasks and executors), it will also keep a reference to those, which will also remain in memory (as well as all transitively referenced objects).
A future does not normally hold references to its “parent(s)” when created through the then*() methods, so they should normally be garbage collected if there are no other references – but pay attention to those, e.g. local variables in the calling thread, reference to a List<CompletableFuture<?>> used in a lambda after allOf() etc.
This Answer only addresses with the 3 followup questions in your "Edit 2".
So in the normal case here in my example i don't have a outside
reference.
I assume that you are referring to the version with the commented out statements.
The CompletableFutures in the thread have never a chance getting completed.
Incorrect. First, A is completed here:
A.complete(new Object());
Next B is completed here:
B.complete(new Object());
Then you call D.join(). Since D is an anyOf stage, this completes when either of A and C completes. A has already completed, so D.join() may not need to wait for C to complete. But since C applies the function asynchronously, it could complete immediately too.
Normally the GC can safely erase both the thread and and the content in there, the CompletableFutures. But I don't think so, that this would happen?
When D.join() returns, the thread terminates. At that point, its local local variables (A, B, C, and D) will be unreachable.
If I abort this by throwing an exception -> the join() is never reached, then i think all would be erased by the GC?
A completes as before, but B, C and D don't.
However, the exception terminates the thread, so the local variables A, B, C, and D then become unreachable.
If I give one of the CompletableFutures to the outside by that AtomicReference, there then could be an chance to unblock the join().
Three points:
The AtomicReference is assigned B so the join() on D is not affected.
As we saw above, it doesn't matter if that a hypothetical join() on outsideReference.value() happens or not for the variables A, B, C, and D. Those variables become unreachable, whichever way the thread terminates.
However, you have now assigned a reference to one of the CompletableFuture objects to a variable which has a different lifetime to the thread. That may mean that that CompletableFuture object stays reachable after the thread has terminated.

The behavior of "Mark & Sweep" in Java, especially for Future object

I'm wondering the lifetime of Future object, which is not bound to a named variable.
I learned that Java adopts mark & sweep style garbage collection.
In that case, any un-named object can be immediately deleted from heap. So I'm wondering if the Future might be swept out from memory even before the Runnable completes, or the memory might never be released.
Any information would be helpful, thanks!
class Main {
void main() {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> { return true; }); // not bind to variable
Thread.sleep(1000);
}
}
I learned that Java adopts mark & sweep style garbage collection.
That is mostly incorrect. Most modern Java garbage collectors are NOT mark & sweep. They are mostly copying collectors that work by evacuating (copying) objects to a "to" space as they are marked. And most Java garbage collectors are also generational.
There is a lot of material published by Oracle about the Java garbage collectors and how they work. And there a good textbooks on the subject too.
In that case, any un-named object can be immediately deleted from heap.
Names have nothing to do with it. References are not names, and neither are variables. Java objects are deleted by the GC only if it finds that they are unreachable; i.e. if no code will never be able to find them again1. Furthermore they are not deleted immediately, or even (necessarily) at the next GC run.
So I'm wondering if the Future might be swept out from memory even before the Runnable completes, or the memory might never be released.
(That's a Callable rather than a Runnable. A Runnable doesn't return anything.)
The answer is no it won't.
The life cycle is something like this:
You call submit passing a Callable.
A CompletableFuture is created.
The CompletableFuture and the Callable are added to the executor's queue.
The CompletableFuture is returned to the caller. (In your case, the caller throws it away.)
At a later point, a worker thread takes the Future and the Callable from the queue, executes the Callable.
Then the worker thread calls complete on the Future to provide the result.
Finally, something will typically call Future.get to obtain the result. (But not in your example.)
In order for the step 6. to work, the CompletableFuture must still be reachable. It won't be thrown away until all references are lost or discarded. Certainly not until after step 6 has completed.
Bottom line: a Java handles the Future just like it would any other (normal) object. Don't worry about it. If anything needs it, it won't disappear.
1 - Reachability is a bit more complicated when you consider, finalization and Reference types. But the same general principal applies. If any code could still see an object, it won't be deleted.
"Submit" means to give something to someone, in this case you're giving a piece of code (in the form of a Callable) to the ExecutorService for later execution. In return, the method returns a Future object that will be updated with the result when it is done.
In order for the ExecutorService to update the Future object, it needs to hold on the Future object too, together with the code reference (the Callable).
Therefore, the ExecutorService maintains references to both the Callable object and the Future object until the job has been completed. Those references makes both objects reachable, preventing the objects from being garbage-collected.
Since your code discarded the returned Future object, the object will become eligible for GC as soon as the job completes, but not before that.

Can a thread lose control after calling a method but before the first instruction of the method?

I need to record the exact order in which a method is called by various threads in Java. I'm supposed to use an object timeProvider which returns non-decreasing long integers. The solution I have come up with is:
public synchronized void method() {
long order = timeProvider.getTime();
// some stuff that can be run concurrently
}
Of course it is a bottleneck because the only place I need to use synchronization is the first line.
So I'm wondering whether it would be safe to change the code to:
public void method() {
//(1)
synchronized (timeProvider) {
long order = timeProvider.getTime();
}
// some stuff that can be run concurrently
}
But in this version I'm worried that the running thread A could lose control in the place marked as (1) - inside the method but before the first instruction. Then another thread B could call the method after A has called it and execute the first intruction and as a result the order from the timeProvider would be recorded wrong. Is this possible?
Yes: The thread executing code inside a method can be halted before the first line.
It might appear as if nothing happens by just calling the method, but actually much happens, especially the creation of the stack frame.

Garbage collection and asynchronous calls / Future objects

Below is a sample code that utilizes the Future interface to make an asynchronous call. I need some clarification about the get() method.
Future<String> future = getAsyncString();
//do something ...
String msg = "";
if (validation)
return;
else
msg = future.get();
//do something else...
return;
The future variable is initialized in a method , so the variable will be soon cleared by the GC after the method's execution as it is no longer used.
So in case that the code enters the if statement , what will be the state of the JVM? How is the JVM going to handle the wrapped result in case that noone is going to read it back? Does it affect the Thread Pool , or the thread Executor?
How is the JVM going to handle the wrapped result in case that noone is going to read it back?
Presumably you got the Future object from an Executor. For this executor to be able to set the result in the Future, it holds a reference to the Future. In other words, just because the method local reference to the object disappears as the call stack is popped, doesn't mean that the Future object (which is on the heap) is automatically eligible for garbage collection.
The async call is not cancelled or anything like that. The executor will perform the call, fill in the result, and presumably drop it's reference to the Future object. At this point the object becomes unreachable and eligible for garbage collection.
If you're certain that your code doesn't keep a reference to the Future object (i.e. leaking it in the // do something... part) then you can be sure that the Future object is (eventually) collected by the GC. (The executor doesn't have any subtle memory leaks here.)
[...] so the variable will be soon cleared by the GC.
To be precise, the variable will be discarded as the call stack is popped. This will eventually cause the Future object to be unreachable and eligible for garbage collection. The object will however typically not be garbage collected immediately as the method returns.
How is the JVM going to handle the wrapped result in case that noone is going to read it back?
If nobody(I mean any program) is going to read it back then GC will take care of it during garbage collection. But that does not mean getAsyncString() will not be executed completely, instead it will complete normally as a normal method completes.
I guess. Scheduled future will have some internal references from threadpools queues until task completion. So it cant be collected by gc before task is complete.
May be there is exists additional abstraction level between future and executor and future can be collected. But im sure that if task submitted it will be runned. No matter, was pointer to future saved or not.
You have guarantee that the object will not be GCed while you are in scope in which reference to it is defined, or there is reference to the object somewhere in code.
This applies to all Objects, and Future makes no difference here.
So, once your method ends, and its call stack is cleared, at some point in the future your object will be eligible for Garbage collection, but certainly not before reference to it exists on the method's call stack.

OutOfMemoryError - why can a waiting Thread not be garbage collected?

This simple sample code demonstrates the problem. I create an ArrayBlockingQueue, and a thread that waits for data on this queue using take(). After the loop is over, in theory both the queue and the thread can be garbage collected, but in practice I soon get an OutOfMemoryError. What is preventing this to be GC'd, and how can this be fixed?
/**
* Produces out of memory exception because the thread cannot be garbage
* collected.
*/
#Test
public void checkLeak() {
int count = 0;
while (true) {
// just a simple demo, not useful code.
final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(2);
final Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
abq.take();
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
// perform a GC once in a while
if (++count % 1000 == 0) {
System.out.println("gc");
// this should remove all the previously created queues and threads
// but it does not
System.gc();
}
}
}
I am using Java 1.6.0.
UPDATE: perform GC after a few iterations, but this does not help.
Threads are top level objects. They are 'special' so they do not follow the same rules as other objects. The do not rely on references to keep them 'alive' (i.e. safe from GC). A thread will not get garbage collected until it has ended. Which doesn't happen in your sample code, since the thread is blocked. Of course, now that the thread object is not garbage collected, then any other object referenced by it (the queue in your case) also cannot be garbage collected.
You are creating threads indefinitely because they all block until ArrayBlockingQueue<Integer> abq has some entry. So eventually you'll get a OutOfMemoryError.
(edit)
Each thread you create will never end because it blocks until the abq queue as one entry.
If the thread is running, the GC isn't going to collect any object that the thread is referencing including the queue abq and the thread itself.
abq.put(0);
should save your day.
Your threads all wait on their queue's take() but you never put anything in those queues.
Your while loop is an infinite loop and its creating new threads continuously. Although you starting the thread execution as soon as its created but the time its taking to complete the task by the thread is greater then the time its taking to create the thread.
Also what are doing with the abq parameter by declaring it inside the while loop?
Based on your edits and other comments. System.gc() doesn't not guarantee a GC cycle. Read my statement above the speed of execution of your thread is lower than the speed of creation.
I checked the comment for the take() method "Retrieves and removes the head of this queue, waiting if no elements are present on this queue." I see you define the ArrayBlockingQueue but you not adding any elements to it so all your thread are just waiting on that method, that is why you getting OOM.
I do not know how threads are implemented in Java, but one possible reason comes to mind why the queues and threads are not collected: The threads may be wrappers for system threads using system synchronization primitives, in which case the GC cannot automatically collect a waiting thread, since it cannot tell whether the thread is alive or not, i.e. the GC simply does not know that a thread cannot be woken.
I can't say what's the best way to fix it, since I'd need to know what you are trying to do, but you could look at java.util.concurrent to see if it has classes for doing what you need.
You start the thread, so all those new threads will be running asynchronously while the loop continues to create new ones.
Since your code is locking, the threads are life references in the system and cannot be collected. But even if they were doing some work, the threads are unlikely to be terminating as quickly as they are created (at least in this sample), and therefore the GC cannot collect all memory and will eventually fail with an OutOfMemoryException.
Creating as many threads is neither efficient nor efficient. If it is not a requirement to have all those pending operations run in parallel, you may want to use a thread pool and a queue of runnables to process.
The System.gc call does nothing because there is nothing to collect. When a thread starts it increments the threads reference count, not doing so will mean the thread will terminate indeterminately. When the thread's run method completes, then the thread's reference count is decremented.
while (true) {
// just a simple demo, not useful code.
// 0 0 - the first number is thread reference count, the second is abq ref count
final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(2);
// 0 1
final Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
abq.take();
// 2 2
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
});
// 1 1
t.start();
// 2 2 (because the run calls abq.take)
// after end of loop
// 1 1 - each created object's reference count is decreased
}
Now, there is a potential race condition - what if the main loop terminates and does garbage collection before the thread t has a chance to do any processing, i.e. it is suspended by the OS before the abq.take statement is executed? The run method will try to access the abq object after the GC has released it, which would be bad.
To avoid the race condition, you should pass the object as a parameter to the run method. I'm not sure about Java these days, it's been a while, so I'd suggest passing the object as a constructor parameter to a class derived from Runnable. That way, there's an extra reference to abq made before the run method is called, thus ensuring the object is always valid.

Categories