Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Locks be garbage collected while locked?

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?

like image 836
Oleg Ryaboy Avatar asked Dec 28 '10 00:12

Oleg Ryaboy


People also ask

What is a lock threading?

The LOCK THREAD statement ensures that no other thread executes. This condition remains in effect until the thread is unlocked (with UNLOCK THREAD) or the thread terminates.

Why is locking required in a threaded server?

Locks are a very important feature that make multithreading possible. Locks are a synchronization technique used to limit access to a resource in an environment where there are many threads of execution.

Can a thread hold more than one lock?

For a thread to work on an object, it must have control over the lock associated with it, it must “hold” the lock. Only one thread can hold a lock at a time. If a thread tries to take a lock that is already held by another thread, then it must wait until the lock is released.


2 Answers

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:

  • knowledge of the Java Language Specification's definition of reachability and other things,
  • experience with implementing JVMs,
  • good old-fashioned logic, and ...
  • I confirmed it by reading the OpenJDK source code (though this doesn't prove anything about JVMs in general.)

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!

like image 65
Stephen C Avatar answered Oct 10 '22 07:10

Stephen C


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

like image 22
Oleg Ryaboy Avatar answered Oct 10 '22 08:10

Oleg Ryaboy