Reputation: 3069
Can Locks (java.util.concurrent.locks.Lock) be garbage collected while locked? Suppose a purely theoretical example:
WeakReference r;
public void foo(){
Lock lock = new ReentrantLock();
r = new WeakReference(lock);
lock.lock();
}
Could lock
be garbage collected after foo()
gets executed? In other words, does lock.lock()
create any strong references back to the lock?
How do you know?
Upvotes: 13
Views: 2696
Reputation: 719376
A locked Lock
can be garbage collected when it is no longer reachable. (The definition of "reachable" in the JLS is: "A reachable object is any object that can be accessed in any potential continuing computation from any live thread." - JLS 12.16.1)
However, a locked Lock
that some thread is waiting on must be executing one of the Lock's lock / tryLock instance methods. For this to happen, the thread must have a reference to the lock; i.e. one that the lock method is currently accessing. Therefore, a locked Lock that some thread is trying to acquire is reachable, and cannot be garbage collected.
In other words, does lock.lock() create any strong references back to the lock?
No. In your example, the strong reference exists in the form of the lock
variable. But suppose that we tweaked your example to get rid of lock
; e.g.
public void do_lock(WeakReference<ReentrantLock> r)
r.get().lock();
}
When you call get()
, it will return a reference to the ReentrantLock
object which will be held in a temporary variable or register, making it strongly reachable. It will continue to be strongly reachable as long as the lock()
call is running. When the lock()
call returns, the ReentrantLock
object may become weakly reachable (again).
How do you know?
How do I know? A combination of:
There is not need to implement Lock
using global queues, and hence no reason to have a hidden reference to the Lock
object that would prevent it becoming unreachable. Furthermore, a Lock
that could not be garbage collected when it was locked would be a storage leak, and a major implementation flaw, and I cannot imagine Doug Lea et al making that mistake!
Upvotes: 19
Reputation: 12066
Technically, the only objects that cannot be garbage collected are the classes loaded by the bootstrap classloader (the rest are outgoing references to the former)
(java.util.concurrent.locks.)Lock(s) are absolutely normal objects, not different than java.util.ArrayList in terms of garbage collection. I have written locks w/ LIFO semantics (or specifically AbstractQueueSynchronized that is not FIFO), that's useful to minimized cache misses since the hottest threads get to work even more. Point is that is absolutely possible to write your own custom locking/sync/atomic code.
Upvotes: 2
Reputation: 3069
It turns out that while we often conceptually think that threads 'obtain' and 'own' locks, it's actually not the case from the implementation perspective. The locks keep references to owning and waiting threads, while the threads have no references to locks, and have no knowledge of the locks they 'own'.
The ReentrantLock implementation is also rather straightforward: there are no static collections of locks, and there are no background maintenance threads that keep track of locks.
Neither creating, nor locking a lock creates any 'hidden' new strong references anywhere, so, in the example above, the lock
can be garbage collected once foo()
is done.
One can verify this by perusing the source code:
http://fuseyism.com/classpath/doc/java/util/concurrent/locks/ReentrantLock-source.html
http://fuseyism.com/classpath/doc/java/util/concurrent/locks/AbstractQueuedSynchronizer-source.html
http://fuseyism.com/classpath/doc/java/util/concurrent/locks/AbstractOwnableSynchronizer-source.html
Upvotes: 2
Reputation: 340406
Assuming that you mean "after foo()
gets executed", the answer is yes - that's really the point of WeakReferences.
You would know that because when you tried to convert the WeakReference
r
back into a regular (or strong) reference, you'd get null
returned:
if (r.get() == null) {
// the lock was garbage collected
}
Upvotes: 0
Reputation: 100151
It can be garbage collected while locked. No strong reference is created by taking the lock. As written, of course, you'd have to set lock to null and run the gc to see the reference go null.
Upvotes: 0
Reputation: 1744
The Lock is not unlike any other object. It depends if some internal Java mechanism references the Lock. But I see no reason why Java should keep a reference to the Lock.
Upvotes: 0