Lock is lost when putting ReentrantLock into HashMap - java

I am trying to make several consumer threads that listen to one producer thread wait until the producer has something to publish. The code that I thought would work "loses" the lock on being put into and taken out of a shared class.
In a controller class I start the thread running with
Server server = new Server();
Thread serverThread = new Thread(server,"Server");
serverThread.start();
Consumer consumer = new Consumer();
Thread consumerThread;
for (int i =0;i<6;i++){
consumerThread = new Thread(consumer,"Consumer No:"+i);
consumerThread.start();
server.threadRefs[i]= consumerThread;
}
The consumer classes put details of threads into the Map as follows:
public class Consumer implements Runnable {
private ReentrantLock lock = new ReentrantLock();
private Condition cond = lock.newCondition();
#Override
public void run() {
long threadID = Thread.currentThread().getId();
while (true) {
try {
lock.lock();
MDRequest.threadLocks.put(threadID, lock);
System.out.println("Thread " + threadID + " lock = " + lock.toString());
cond.await();
System.out.println("Thread " + threadID + " done waiting");
} catch (InterruptedException ex) {
System.out.println("Interruped " + threadID);
} finally {
lock.unlock();
}
System.out.println("Finished " + threadID);
}
}
The shared class is simply:
public class MDRequest {
protected static ConcurrentHashMap<Long, ReentrantLock> threadLocks = new ConcurrentHashMap<Long, ReentrantLock>();
The Server has the following run() method:
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
Set<Long> keys = MDRequest.threadLocks.keySet();
Long[] threadIDs = keys.toArray(new Long[1]);
// generates a random series of numbers for each thread and notifies threads about them
while (true) {
Random random = new Random();
int threadRef = random.nextInt(5);
System.out.println("About to signal thread " + threadIDs[threadRef].toString());
// notify the thread of the data
ReentrantLock lock = MDRequest.threadLocks.get(threadIDs[threadRef]);
System.out.println("Thread " + threadIDs[threadRef].toString() + " lock = " + lock.toString());
Condition cond = lock.newCondition();
cond.signal();
lock.unlock();
}
The output is as follows:
Thread 11 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:0]
Thread 12 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:1]
Thread 13 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:2]
Thread 14 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:3]
Thread 15 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:4]
Thread 16 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Locked by thread Consumer No:5]
About to signal thread 14
Thread 14 lock = java.util.concurrent.locks.ReentrantLock#272d7a10[Unlocked]
Exception in thread "Price Server" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1885)
at faster.Server.run(Server.java:46)
at java.lang.Thread.run(Thread.java:695)
From the output int the Server class I can see that when I read the lock out of the Map it now has a status of "Unlocked". When it was put in it had a status of Locked on thread 14.
Why does the reference to the ReentrantLock "lose" the lock?
Is there a way of sharing the lock between the multiple consumer threads and the server thread in a way that the lock is not lost?

The problem you are facing is may be because of the following line in Server
Condition cond = lock.newCondition();
cond.signal();
lock.unlock();
Do you need to call unlock() from the Server for a Lock which is locked by the Consumer? I think calling signal() will suffice.
Think about this.

The problem is thread in Server class tries to unlock but has not lock the Lock
lock.unlock();
Please see ReentrantLock documentation where is clearly stated:
If the current thread is not the holder of this lock then IllegalMonitorStateException is thrown.

Related

Java: How to solve Readers-Writer Problem?

I want to implement a solution for Readers-Writer problem. The main rule is, only one writer can write at a time and no other writer or reader can write or read, but if a writer doesn't write , multiple readers can read. In the main class, I tried to run threads with executorService.execute but i had some problems i guess. I don't know much about executorService. The program never ends and I guess there is some output problems.
My code is below:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class ReaderWriter {
public static void main(String [] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
ReadWriteLock RW = new ReadWriteLock();
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
}
}
class ReadWriteLock{
static Semaphore readLock = new Semaphore(1);
static Semaphore writeLock = new Semaphore(1);
volatile static int readCount = 0;
public void readLock() throws InterruptedException {
readLock.acquire();
readCount++;
if (readCount == 1) {
writeLock.acquire();
}
readLock.release();
//Reading section
System.out.println("Thread "+Thread.currentThread().getName() + " is READING");
Thread.sleep(1500);
System.out.println("Thread "+Thread.currentThread().getName() + " has FINISHED READING");
//Releasing section
readLock.acquire();
readCount--;
if(readCount == 0) {
writeLock.release();
}
readLock.release();
}
public void writeLock() throws InterruptedException {
writeLock.acquire();
System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
Thread.sleep(2500);
writeLock.release();
System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
}
}
class Writer implements Runnable
{
private ReadWriteLock RW_lock;
public Writer(ReadWriteLock rw) {
RW_lock = rw;
}
public void run() {
while (true){
try {
RW_lock.writeLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Reader implements Runnable
{
private ReadWriteLock RW_lock;
public Reader(ReadWriteLock rw) {
RW_lock = rw;
}
public void run() {
while (true){
try {
RW_lock.readLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And the output is not right i think for this problem:
Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-2 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-2 has finished WRITING
Thread pool-1-thread-3 is WRITING
Thread pool-1-thread-3 has finished WRITING
Thread pool-1-thread-4 is WRITING
Thread pool-1-thread-4 has finished WRITING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-8 has FINISHED READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-6 has FINISHED READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-7 has FINISHED READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-8 has FINISHED READING
In this output there is 2 writers writing at the same time.
OUTPUT EDIT:
Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-1 is WRITING
Thread pool-1-thread-1 has finished WRITING
Thread pool-1-thread-4 is WRITING
Thread pool-1-thread-4 has finished WRITING
Thread pool-1-thread-3 is WRITING
Thread pool-1-thread-3 has finished WRITING
Thread pool-1-thread-2 is WRITING
Thread pool-1-thread-2 has finished WRITING
Thread pool-1-thread-8 is READING
Thread pool-1-thread-7 is READING
Thread pool-1-thread-5 is READING
Thread pool-1-thread-6 is READING
Thread pool-1-thread-8 has FINISHED READING
Thread pool-1-thread-7 has FINISHED READING
Thread pool-1-thread-5 has FINISHED READING
Thread pool-1-thread-6 has FINISHED READING
The program never ends and i guess there is some output problems.
Add a flag into the ReadWriteLock class to signals the Threads when they should stop working:
private final AtomicBoolean keep_working = new AtomicBoolean(true);
add a method in the ReadWriteLock class to signal the threads to stop:
public void stopThreads(){
keep_working.set(false);
}
and add the method to query the flag:
public boolean keepWorking(){
return keep_working.get();
}
adapt the Writer and Reader run methods, accordingly:
public void run() {
while (RW_lock.keepWorking()){
...
}
}
on the main class add a call to the methods ExecutorService.awaitTermination(), ReadWriteLock.stopThreads, and ExecutorService.shutdown():
public static void main(String [] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
ReadWriteLock RW = new ReadWriteLock();
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Writer(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
executorService.execute(new Reader(RW));
try {
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) { // ...}
RW.stopThreads();
executorService.shutdown();
}
And the output is not right i think for this problem:
(...)
In this output there is 2 writers writing at the same time.
That is because in :
public void writeLock() throws InterruptedException {
writeLock.acquire();
System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
Thread.sleep(2500);
writeLock.release();
System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
}
you release the lock before printing "has finished WRITING" therefore, a thread waiting for that lock to be released enters and prints "is WRITING" before the first thread has time to print "has finished WRITING". So you need to change the code to:
public void writeLock() throws InterruptedException {
writeLock.acquire();
System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
Thread.sleep(2500);
System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
writeLock.release();
}
The main rule is, only one writer can write at a time and no other
writer or reader can write or read, but if a writer doesn't write ,
multiple readers can read.
Actually, you can take advantage of the Java ReadWriteLock Interface.
A ReadWriteLock maintains a pair of associated locks, one for
read-only operations and one for writing. The read lock may be held
simultaneously by multiple reader threads, so long as there are no
writers. The write lock is exclusive. All ReadWriteLock
implementations must guarantee that the memory synchronization effects
of writeLock operations (as specified in the Lock interface) also hold
with respect to the associated readLock. That is, a thread
successfully acquiring the read lock will see all updates made upon
previous release of the write lock.
A read-write lock allows for a greater level of concurrency in
accessing shared data than that permitted by a mutual exclusion lock.
It exploits the fact that while only a single thread at a time (a
writer thread) can modify the shared data, in many cases any number of
threads can concurrently read the data (hence reader threads). In
theory, the increase in concurrency permitted by the use of a
read-write lock will lead to performance improvements over the use of
a mutual exclusion lock. In practice this increase in concurrency will
only be fully realized on a multi-processor, and then only if the
access patterns for the shared data are suitable.
By using that interface you could simplify significantly the readLock and writeLock methods, to something as follows:
public void readLock() throws InterruptedException {
shared_resource.readLock().lock();
System.out.println("Thread "+Thread.currentThread().getName() + " is READING");
Thread.sleep(1500);
System.out.println("Thread "+Thread.currentThread().getName() + " has FINISHED READING");
shared_resource.readLock().unlock();
}
public void writeLock() throws InterruptedException {
shared_resource.writeLock().lock();
System.out.println("Thread "+Thread.currentThread().getName() + " is WRITING");
Thread.sleep(2500);
System.out.println("Thread "+Thread.currentThread().getName() + " has finished WRITING");
shared_resource.writeLock().unlock();
}
To complete, you should add a variable that counts the number of writes and reads. So that if there is nothing written, the read threads should wait, and in the meantime, the write thread should write something, and so.
You need to invoke the shutdown or shutdownAndAwaitTermination method of the ExecutorService in the main method.

ReentrantReadWriteLock fails to get lock even when its state is Unlocked

I am trying to get lock on a thread using following piece of code:
Lock lock = readLock ? getLock(key).readLock() : getLock(key).writeLock();
try {
boolean locked = lock.tryLock(DEFAULT_TRY_TIME, DEFAULT_TRY_TIME_UNIT); //line 3
// If false, lock is not acquired
if (!locked) {
throw new TryLockTimeoutException(
key + ": Failed to acquire " + lock + " within " + DEFAULT_TRY_TIME_STRING);
}
}
Line 3 returns false after 30 minutes hence TryLockTimeoutException is thrown with error as:
com.concurrent.TryLockTimeoutException: keyIp : Failed to acquire java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock#74be2cee[Unlocked] within 30MINUTES
at com.concurrent.NeAccessLockMap.acquireReadOrWriteLock(NeAccessLockMap.java:72)
Notice that lock state is shown as Unlocked in error.
I am not able to understand why would this happen? Why thread is not able to get lock even when the lock is free.
In your example you try to acquire a write lock, but the read lock is already locked, which prevents you from acquiring the write lock.
Because you can either have one or more read locks acquired, or a single write lock acquired, the write lock is marked as Unlocked when there are read locks acquired.
Try the following code:
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
new Thread() {
#Override
public void run() {
readWriteLock.readLock().lock();
try {
// block the read lock
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
if (!readWriteLock.writeLock().tryLock(1, TimeUnit.SECONDS)) {
System.out.println(readWriteLock);
System.out.println(readWriteLock.readLock());
System.out.println(readWriteLock.writeLock());
}
would have output like:
java.util.concurrent.locks.ReentrantReadWriteLock#31221be2[Write locks = 0, Read locks = 1]
java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock#377dca04[Read locks = 1]
java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock#728938a9[Unlocked]

Java-Cannot terminate main thread with return;

here is my code of main class, because only thread 3 will change the shutdown and main will not read return until thread 3 close so there no need to synchronize it. When I try to run it, the "shutdown" is printed but eclipse say that the program is still running
static Boolean shutdown = false;
public static void main(String[] args) throws InterruptedException, IOException{
System.out.println("Start Server");
final int SocketListSize = 100000;
final int AccListSize = 1000000;
ServerSocket serverSocket;
List<Socket> socketList = Collections.synchronizedList(new ArrayList<Socket>(SocketListSize));
List<Request> requestList = Collections.synchronizedList(new ArrayList<Request>(SocketListSize));
ArrayList<BankAccount> bankAccList = new ArrayList<BankAccount>(AccListSize);
serverSocket = new ServerSocket(1234);
serverSocket.setSoTimeout(50000);
Thread Thread_1 = new Thread(new scanSocketThread(serverSocket, socketList));
Thread Thread_2 = new Thread(new getRequestThread(socketList, requestList));
Thread Thread_3 = new Thread(new ServiceThread(requestList, bankAccList));
Thread_1.start();
System.out.println("thread 1 start");
Thread_2.start();
System.out.println("thread 2 start");
Thread_3.start();
System.out.println("thread 3 start");
Thread_3.join();
System.out.println("thread 3 close");
Thread_1.interrupt();
System.out.println("thread 1 close");
Thread_2.interrupt();
System.out.println("thread 2 close");
if(shutdown == true){
System.out.println("shutdown");
return;
}
Here is what I get
thread 3 close
thread 1 close
thread 2 close
shutdown
If you're looking to kill your program, you can use System.exit(0); instead of the return statement you have now.
More: What are the differences between calling System.exit(0) and Thread.currentThread().interrupt() in the main thread of a Java program?

Cleaning up after two threads finish execution

I have an application that is running jobs that require two threads for every job. The two threads normally do some work and finish shortly after each other. Then after the second thread finishes I need to do some cleanup but since the threads are doing some network IO, it is possible for one thread to get blocked for a long time. In that case, I want the cleanup to take place a few seconds after the first thread finishes.
I implemented this behaviour with the following piece of code in a callback class:
private boolean first = true;
public synchronized void done() throws InterruptedException {
if (first) {
first = false;
wait(3000);
// cleanup here, as soon as possible
}
else {
notify();
}
}
Both threads invoke the done() method when they finish. The first one will then block in the wait() for at most 3 seconds but will be notified immediately when the seconds thread invokes the done() method.
I have tested this implementation and it seems to work well but I'm am curious if there's a better way of doing this. Even though this implementation doesn't look too complicated, I'm afraid that my program will deadlock or have some unsuspected synchronization issue.
I hope I understood your need. You want to wait for thread-a to complete and then wait either 3 seconds or for the end of thread-b.
It is better to use the newer Concurrent tools instead of the old wait/notify as there are so many edge cases to them.
// Two threads running so count down from 2.
CountDownLatch wait = new CountDownLatch(2);
class TestRun implements Runnable {
private final long waitTime;
public TestRun(long waitTime) {
this.waitTime = waitTime;
}
#Override
public void run() {
try {
// Wait a few seconds.
Thread.sleep(waitTime);
// Finished! Count me down.
wait.countDown();
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
}
public void test() throws InterruptedException {
// ThreadA
Thread threadA = new Thread(new TestRun(10000), "Thread A");
// ThreadB
Thread threadB = new Thread(new TestRun(30000), "Thread B");
// Fire them up.
threadA.start();
threadB.start();
// Wait for all to finish but threadA must finish.
threadA.join();
// Wait up to 3 seconds for B.
wait.await(3, TimeUnit.SECONDS);
System.out.println(new Date() + ": Done");
threadB.join();
}
happily prints:
Tue Sep 15 16:59:37 BST 2015: Thread A - Finished
Tue Sep 15 16:59:40 BST 2015: Done
Tue Sep 15 16:59:57 BST 2015: Thread B - Finished
Added
With the new clarity - that the end of any thread starts the timer - we can use a third thread for the cleanup. Each thread must call a method when it finishes to trigger the cleanup mechanism.
// Two threads running so count down from 2.
CountDownLatch wait = new CountDownLatch(2);
class TestRun implements Runnable {
private final long waitTime;
public TestRun(long waitTime) {
this.waitTime = waitTime;
}
#Override
public void run() {
try {
// Wait a few seconds.
Thread.sleep(waitTime);
// Finished! Count me down.
wait.countDown();
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
// Record that I've finished.
finished();
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
}
Runnable cleanup = new Runnable() {
#Override
public void run() {
try {
// Wait up to 3 seconds for both threads to clear.
wait.await(3, TimeUnit.SECONDS);
// Do your cleanup stuff here.
// ...
System.out.println(new Date() + ": " + Thread.currentThread().getName() + " - Finished");
} catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " - Interrupted");
}
}
};
final AtomicBoolean cleanupStarted = new AtomicBoolean(false);
private void finished() {
// Make sure I only start the cleanup once.
if (cleanupStarted.compareAndSet(false, true)) {
new Thread(cleanup, "Cleanup").start();
}
}
public void test() throws InterruptedException {
// ThreadA
Thread threadA = new Thread(new TestRun(10000), "Thread A");
// ThreadB
Thread threadB = new Thread(new TestRun(30000), "Thread B");
// Fire them up.
threadA.start();
threadB.start();
System.out.println(new Date() + ": Done");
}
As done method is synchronized, so only one thread can execute at a time, with this second will wait to send notify until first finishes its whole job, which might cause performance bottleneck.
I would rather design it with short synchronized block which would primarily update the boolean first.

Misunderstanding ExecutorService - I think

I want to start a group of 10 threads. In my main program constructor I am using:
executor = Executors.newFixedThreadPool(NTHREADS);
Callable<String> poller;
for (int i = 0; i < NTHREADS; ++i) {
Future<String> future = executor.submit(new Poller(0x3A, m_socket, ds_in, ds_out, socketLock));
set.add(future);
}
For the call() method in class Poller I have :
public String call()
{
// This has to be set here, otherwise all threads will have a name of "main".
myID = Thread.currentThread().getName();
boolean shutup_loop = true;
do {
System.out.println("Hey, I'm thread " + myID);
System.out.println("Hey, I'm thread " + Thread.currentThread().getName());
try {
Thread.sleep(10);
}
catch (java.lang.InterruptedException e) {
System.out.println("thread " + myID + ": " + e);
}
// Do if you want the printing to all match up on one line
synchronized (this) {
ByteArrayOutputStream baos = SendReceive(pollPacket);
System.out.print(myID + ": ");
if (baos != null) {
printStuff(baos);
System.out.println();
}
notify();
}
} while (shutup_loop);
return "poller is finished";
}
These Poller threads are calling SendReceive(), part of the Poller class:
public synchronized ByteArrayOutputStream SendReceive(byte[] toSend)
{
System.out.println("START");
System.out.println("SendReceive()1 " + myID);
System.out.println("SendReceive()2 " + Thread.currentThread().getName());
System.out.println("END");
try {
ds_out.write(toSend, 0, toSend.length);
ds_out.flush();
}
catch (java.io.IOException e) {
System.out.println("thread " + myID + ": " + e);
}
try {
m_socket.setSoTimeout(200); // <-- might need tweaking
}
catch (java.net.SocketException e) {
System.out.println("thread " + myID + ": " + e);
}
ByteArrayOutputStream baos = null;
try {
baos = getResponse(ds_in);
}
catch (java.io.IOException e) {
System.out.println("thread " + myID + ": " + e);
}
return baos;
}
Because this is a synchronized method I would expect the output to resemble:
START
SendReceive()1 pool-1-thread-1
SendReceive()2 pool-1-thread-1
END
START
SendReceive()1 pool-1-thread-2
SendReceive()2 pool-1-thread-2
END
Instead it is doing:
START
START
START
START
START
START
SendReceive()1 pool-1-thread-2
START
START
START
SendReceive()1 pool-1-thread-6
SendReceive()1 pool-1-thread-7
SendReceive()2 pool-1-thread-2
SendReceive()1 pool-1-thread-3
SendReceive()2 pool-1-thread-6
SendReceive()1 pool-1-thread-1
SendReceive()1 pool-1-thread-9
SendReceive()1 pool-1-thread-8
SendReceive()2 pool-1-thread-9
END
...
What gives?
synchronized uses this as a lock: in your case you have several Poller instances so each uses a different lock. To make it work you need a common lock:
either make the method static
or use a common private static final Object lock = new Object(); and use synchronized(lock) {...}
If what you are after is sharing the socket between pollers, you do not need to use an executor service. You need to serialize the use of the socket anyway, so you can just loop over the list of poll tasks and hand the current one the socket to work with.
On the other hand, if you really want to poll in parallel using the same socket, your network protocol should support that by allowing you to send a poll message without having to wait for a response to it; you would have multiple requests in flight. But I suspect that's a bigger and different problem that what you are trying to solve.

Categories

Resources