java ReentrantReadWriteLock "max lock count exceeded" troubleshooting - java

I'm debugging an error from the application on a ReadWriteLock, as shown below in the stack traces. For the particular ReentrantReadWriteLock, you can imagine there's a global lock in an RPC server. All RPC worker threads will acquire a read lock to serve, and one checkpointing thread will acquire the write lock to take a checkpoint.
java.lang.Error: Maximum lock count exceeded
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.fullTryAcquireShared(ReentrantReadWriteLock.java:528)
at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryAcquireShared(ReentrantReadWriteLock.java:488)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1303)
at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.lockInterruptibly(ReentrantReadWriteLock.java:772)
...some application call stack acquiring a ReadWriteLock.readLock()
From the stack trace, I'm only able to tell the lock count is on the ReadLock(not the WriteLock). From the java code, the "max count" is exceeded when it is 65535. My questions are:
Does that mean 65535 read lock holders? Or one thread holding the thread with 65535 recursions? Or a combination of both? How do I find out which thread is doing the heavy recursion?
I'm almost certain that there are around 500 RPC worker threads serving(not 65535 threads), therefore some threads must be acquiring the lock more than 1 time, a recursive operation somewhere essentially doing the logic below:
// pseudo code
public void serveRPC() {
// Always using try-with-resource so I assume all locks are released properly
try (acquireSharedLock(stateLock)) {
// something calling serveRPC so recursively acquiring the lock in the same thread!
}
}
There are some options I can think of, what are your suggestions? Thanks!
// Option 1: check the holder count on every lock acquisition
public AutoCloseable<Lock> acquireStateLockShared() {
// Question: is this number accurate?
// Question: does lock.getReadLockCount() also matter?
if (stateLock.getReadHoldCount() > 1) { // print something }
...
}
// Option 2: Have something like a global bookkeeper to record the usage of each thread
Map<Long, LongAdder> recordTable = ...
public AutoCloseable<Lock> acquireStateLockShared() {
recordTable.computeIfAbsent(Thread.currentThread().getId(), k -> new AtomicInteger(0)).increment()
..
}
// when the AutoCloseable is closed, reduce in the recordTable

Related

Is it possible to block a thread until AtomicBoolean contains a desired value?

I've got a system with many writers and a single reader, each running in a separate thread. The writers notify the reader when work is available, and the reader blocks until it is notified.
Given the number of writers, I want to use a lock-free implementation to notify the reader. Every time the reader wakes up, it resets the notification flag, does some work, and blocks waiting for more notifications to arrive.
Essentially I'm looking for the equivalent of an AtomicBoolean with an ability to block until its value becomes true.
What I've tried so far:
My current implementation uses a Semaphore.
The semaphore starts out with no permits.
The reader blocks trying to acquire a permit.
Writers invoke Semaphore.release() in order to notify the reader.
The reader invokes Semaphore.drainPermits(), does some work, and blocks again on Semaphore.acquire.
What I don't like about the Semaphore approach:
It seems a bit heavy-handed. I only care about about the first notification arriving. I don't need to keep a count of how many other notifications came in.
Semaphores throw an exception if their count surpasses Integer.MAX_VALUE. This is more of a theoretical problem than practical but still not ideal.
Is there a data structure that is equivalent to AtomicBoolean with an ability to block waiting on a particular value?
Alternatively, is there a thread-safe manner to ensure that Semaphore's number of permits never surpass a certain value?
BlockingQueue<Singleton> would do this adequately.
You would create, for example, an ArrayBlockingQueue<Singleton>(1), and then your waiter would look like:
queue.take();
… and the notifier would look like:
queue.offer(Singleton.INSTANCE)
… with the use of offer ensuring that multiple releases are combined together.
FYI: The Java language includes a general mechanism for threads to await arbitrary events caused by other threads. It's rather primitive, and in many applications, you'd be better off using some higher-level, problem-specific tool such as BlockingQueue, CompletableFuture, CountdownLatch, etc. But, for those problems where the higher-level classes all "feel a bit heavy-handed," the Object class has object.wait(), object.notify(), and object.notifyAll().*
The idea is,
You have some test() that yields a boolean result,
There is a mutex that threads are required to own when performing the test or changing its result, and
There is at least one thread that needs to wait until the test yields true before it can proceed.
final Object mutex = new Object();
public boolean test() { ... }
public boolean procedureThatAffectsTheTestResult() { ... }
public boolean procedureThatRequiresTestResultToBeTrue() { ... }
A thread that needs to wait until the test result is true can do this:
synchronized (mutex) {
while (! test()) {
try {
mutex.wait();
}
catch (InterruptedException ex) {
...use your shameful imagination here...
}
}
procedureThatRequiresTestResultToBeTrue();
}
Any thread that can change the test result should do it like so:
synchronized (mutex) {
procedureThatAffectsTheTestResult();
mutex.notifyAll(); //or, mutex.notify() *IF* you know what you are doing.
}
The mutex.notifyAll() call will wake up every thread that happens to be sleeping in a mutex.wait() call at that same moment. mutex.notify() is trickier, but it will improve the performance of some applications because it will arbitrarily choose just one thread if more than one is waiting.
You may be wondering how a thread could ever enter a synchronized (mutex) block to change the test() result when another thread already is wait()ing inside another synchronized (mutex) block. The secret is that mutex.wait() temporarily unlocks the mutex while it is waiting, and then it guarantees to re-lock the mutex before returning or throwing an exception.
For a more complete description of when and why and how to use this feature, see the tutorial: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
* You can also do practically the same thing using a Condition object and a ReentrantLock, but that's a topic for another day.

Multi Thread Java in case of static array - one thread is updating and another thread is reading array

There is array Link ports[4] which is defined as static and part of main thread. In my project, there are various producer and consumer threads which are using this array by using static reference i.e. using name of class to access array. In some part of project, his array is getting update and other part of project this array is being read. How should I use synchronized, wait , notify or join so as I can maintain consistency in my code?
class Router{ \\ on main thread
static Link[] ports = new Link[4];
void processCnnect {
else if(Router.ports[i]==null && processPort > 1023 && processPort<=65535)
{
Router.ports[i] =new Link(rd,rd_c);
}
}
class ServerThread extends Thread
{
// reading then updating Router.ports[]
}
There are some threads which perform heart beat mechanism by sending packets to other consumer (receiver) like alive messages. Its a mix of multi threading and socket programming.
Most probably the server thread is the one which writes into ports, and the worker threads service the individual ports. In that case, you can have a read-write lock.
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
server thread:
class ServerThread extends Thread
{
readWriteLock.readLock().lock();
// read ports here
readWriteLock.readLock().unlock();
// if these ports need to be updated, acquire the write lock
readWriteLock.writeLock().lock();
// only one writer can enter this section,
// and only if no threads are currently reading.
readWriteLock.writeLock().unlock();
}
worker threads:
class WorkerThread extends Thread
{
readWriteLock.readLock().lock();
// read ports here, and service them
readWriteLock.readLock().unlock();
}
Even though ReentrantReadWriteLock is a good option, you may also consider implementing of Optimistic Read through StampedLock. When the number of readers is significantly greater than the numbers of writers, Optimistic Read outperforms the others. Moreover, in a practical scenario, both read and write operations rarely happen at the same time. Therefore, optimistic read works most of the time.
private final StampedLock stLock = new StampedLock();
Reader
long stamp = stLock.tryOptimisticRead();
// read ports here!
if (stLock.validate(stamp) == false) {
// optimistic reading fails (write occurred) - read again through read-lock.
stamp = stLock.readLock();
try {
// read ports here!
} finally {
stLock.unlockRead(stamp);
}
}
Writer
long stamp = stLock.writeLock();
try {
// write ports here!
} finally {
stLock.unlockWrite(stamp);
}
How should I use synchronized, wait , notify or join so as I can maintain consistency in my code?
synchronized - You can maintain consistency through synchronized, but it is not a good choice here. If a code segment or method is synchronized only one thread can execute that block or method at one time. In a typical read/write scenario, it is not efficient because multiple read operations are not mutually exclusive.
wait()/notify() - If your concern is just getting the most up-to-date value then there is nothing to do with wait()/notify(). They are designed to block (release) a thread until (when) a specific condition is met.
join() - allows one thread to wait until another thread completes its execution.

Confused with custom read write lock implementation

I have seen some posts about the custom read-write lock implementation in java using wait/notify. It looks like:
public class ReadWriteLock{
private int readers;
private int writers;
private int writeRequests;
public synchronized void lockRead() throws InterruptedException{
while(writers > 0 || writeRequests > 0){
wait();
}
readers++;
}
public synchronized void unlockRead(){
readers--;
notifyAll();
}
public synchronized void lockWrite() throws InterruptedException{
writeRequests++;
while(readers > 0 || writers > 0){
wait();
}
writeRequests--;
writers++;
}
public synchronized void unlockWrite() throws InterruptedException{
writers--;
notifyAll();
}
}
I cannot comprehend how it could correctly work, unless I have not understood correctly how wait/notify really works. Assuming the read requests and consequently Threads are more, my questions are:
If read Threads acquire repeatedly the lock on the instance, how could a write Thread increase the variable writeRequests, since it can be increased only within a synchronized method. Hence a Thread should acquire first the lock to do it (if I am not mistaken). As long as a read Thread calls wait only if writeRequests or writers are greater than 0 , how can a write Thread have the chance to acquire the lock?
Based on the above presumptions and statements, how could more than one read Threads access a method at the same time, since they should first call lockRead() which is synchronized as well?
Edit : After seeing you edit to the question, you're asking what happens when multiple threads call wait() inside the same synchronized blocks - see this for a detailed explanation on what is called 'releasing the monitor' - http://www.artima.com/insidejvm/ed2/threadsynchP.html
To simplify things:
Synchronized methods are like synchronized(this) blocks.
calling wait() inside synchronized blocks release the lock and switches the thread to WAITING state. in this scenario other threads can acquire the lock on the same object and possibly notify the other waiting threads on state change (your unlock methods demonstrate that) by using the same object waited on (this in our case, because you're using synchronized methods)
If you map the possible scenarios for calling each method according to that priniciple you can see that methods are either non-waiting ( unlockRead()/unlockWrite()) - meaning they can block on mutual exclusion upon entry, but don't run any blocking code(and end swiftly).
Or, they are waiting but non-blocking ( lockRead()/lockWrite()) - Just like the unlock methods with the addition their execution could potentially be stalled, however they don't block, but rather wait in such scenarios.
So in any case you can consider your code as non-blocking and therefor it doesn't pose any real issue ( at least none that I can see ).
That said, you should protect against unlocking non-existent locks, causes that'll cause an undesired behavior where counters would go below 0 ( which would in turn affect the lock methods)

Deadlock in the semaphore function

Question 1:
I was reading into Hard-core Multi-threading in Java and did bump up into the semaphore example below.
package com.dswgroup.conferences.borcon.threading;
public class ResourceGovernor {
private int count;
private int max;
public ResourceGovernor(int max) {
count = 0;
this.max = max;
}
public synchronized void getResource(int numberof) {
while (true) {
if ((count + numberof) <= max) {
count += numberof;
break;
}
try {
wait();
} catch (Exception ignored) {}
}
}
public synchronized void freeResource(int numberof) {
count -= numberof;
notifyAll();
}
}
I feel this can lead to deadlock in the below scenario :
All resources are being used and a new thread asks for resources that are not available.
Since it waits inside the synchronized function, the other threads that are using the resources are not able to free the resources as the freeResource function is also synchronized and that they can't enter the function as the waiting thread has taken the object level lock of ResourceGovernor
There is another issue that one has not validated if a thread is trying to release more no. of resources than it acquired. But this issue is secondary and can be easily fixed by having the synchronized map of thread name and resource count.
But can i safely say that i diagnosed the 1st problem correctly. (Need to doublecheck since its published for a long time on embarcadero.com)
Question 2:
Can i safely say that a semaphore with only 1 resource has the same behaviour as a mutex lock?
All resources are being used and a new thread asks for resources that are not available. Since it waits inside the synchronized function, the other threads that are using the resources are not able to free the resources as the freeResource function is also synchronized and that they can't enter the function as the waiting thread has taken the object level lock of ResourceGovernor
You've missed the fact that calling wait() relinquishes the monitor, so other synchronized code is able to execute. From the docs for wait():
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
For your second question:
Can I safely say that a semaphore with only 1 resource has the same behaviour as a mutex lock?
I suspect so, although the implementation you've shown doesn't actually stop you from calling freeResource several times. It's a slightly odd implementation in that I normally see semaphores counting the number of resources remaining rather than the number of resources taken - although they're equivalent, of course.
Question 2 : Yes it is similar to mutex. But although mutexes and semaphores have similarities in their implementation, they should always be used differently. Nice Explanation Here

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