Proper implementation of producer-consumer scenario and "graceful" termination of thread pool - java

I am working on my first multi-threaded project and thus have a couple of things that I am unsure of. Details on my setup was on a previous question, in short: I have a thread pool implemented by Executors.newFixedThreadPool(N). One thread is given an action which does a series of queries to local and remote resources and iteratively populates an ArrayBlockingQueue, while the rest of the threads invoke take() method on the queue and process the objects in the queue.
Even though small and supervised tests seem to run OK, I am unsure about how I handle special scenarios such as the beginning (the queue has no items yet), the end (the queue is emptied), and any eventual InterruptedExceptions. I have done some reading here on SO, which then led me to two really nice articles by Goetz and Kabutz. The consensus seems to be that one should not ignore these exceptions. However I am unsure how the examples supplied relates to my situation, I have not invoked thread.interrupt() anywhere in my code... Speaking of which, I'm getting unsure if I should have done so...
To sum it up, given the code below, how do I best handle the special cases, such as termination criteria and the InterrruptedExceptions? Hope the questions make sense, otherwise I'll do my best to describe it further.
Thanks in advance,
edit: I have been working on the implementation for a while now, and I have come across a new hiccup so I figured I'd update the situation. I have had the misfortune of coming across ConcurrentModificationException which was most likely due to incomplete shutdown/termination of the thread pool. As soon as I figured out I could use isTerminated() I tried that, then I got a IllegalMonitorStateException due to an unsynchronized wait(). The current state of the code is below:
I have followed some of the advices from #Jonathan's answer, however I don't think his proposal works quite like what I need/want. The background story is the same as I have mentioned above, and relevant bits of code are as follows:
Class holding/managing the pool, and submission of runnables:
public void serve() {
try {
this.started = true;
pool.execute(new QueryingAction(pcqs));
for(;;){
PathwayImpl p = bq.take();
if (p.getId().equals("0")){
System.out.println("--DEBUG: Termination criteria found, shutdown initiated..");
pool.shutdown();
// give 3 minutes per item in queue to finish up
pool.awaitTermination(3 * bq.size(), TimeUnit.MINUTES);
break;
}
int sortMethod = AnalysisParameters.getInstance().getSort_method();
pool.submit(new AnalysisAction(p));
}
} catch (Exception ex) {
ex.printStackTrace();
System.err.println("Unexpected error in core analysis, terminating execution!");
System.exit(0);
}finally{ pool.shutdown(); }
}
public boolean isDone(){
if(this.started)
return pool.isTerminated();
else
return false;
}
Elements are added to the queue by the following code on located in a separate class:
this.queue.offer(path, offer_wait, TimeUnit.MINUTES);
... motivation behind offer() instead of take() is as Jonathan mentioned. Unforeseen blocks are annoying and hard to figure out as my analysis take a long time as it is. So I need to know relatively quick if the fails due to a bad block, or if it's just crunching numbers...
and finally; here's the code in my test class where I check the interaction between the "concurrency service" (named cs here) and the rest of the objects to be analyzed:
cs.serve();
synchronized (this) {
while(!cs.isDone())
this.wait(5000);
}
ReportGenerator rg = new ReportGenerator();
rg.doReports();
I realize that this has been a VERY long question but I tried to be detailed and specific. Hopefully it won't be too much of a drag, and I apologize in case it is...

Instead of using take, which blocks, use something more like this:
PathwayImpl p = null;
synchronized (bq) {
try {
while (bq.isEmpty() && !stopSignal) {
bq.wait(3000); // Wait up to 3 seconds and check again
}
if (!stopSignal) {
p = bq.poll();
}
}
catch (InterruptedException ie) {
// Broke us out of waiting, loop around to test the stopSignal again
}
}
This assumes that the block is enclosed in some sort of while (!stopSignal) {...}.
Then, in the code that adds to the queue, do this:
synchronized (bq) {
bq.add(item);
bq.notify();
}
As for InterruptedExceptions, they are good for signaling the thread to test the stop signal immediately, instead of waiting until the next timeout-and-test. I suggest just testing your stop signal again, and possibly logging the exception.
I use them when signaling a panic, versus a normal shutdown, but it is rare that such a situation is necessary.

Related

How to check if certain object is locked in Java? [duplicate]

I have a process A that contains a table in memory with a set of records (recordA, recordB, etc...)
Now, this process can launch many threads that affect the records, and sometimes we can have 2 threads trying to access the same record - this situation must be denied. Specifically if a record is LOCKED by one thread I want the other thread to abort (I do not want to BLOCK or WAIT).
Currently I do something like this:
synchronized(record)
{
performOperation(record);
}
But this is causing me problems ... because while Process1 is performing the operation, if Process2 comes in it blocks/waits on the synchronized statement and when Process1 is finished it performs the operation. Instead I want something like this:
if (record is locked)
return;
synchronized(record)
{
performOperation(record);
}
Any clues on how this can be accomplished?
Any help would be much appreciated.
Thanks,
One thing to note is that the instant you receive such information, it's stale. In other words, you could be told that no-one has the lock, but then when you try to acquire it, you block because another thread took out the lock between the check and you trying to acquire it.
Brian is right to point at Lock, but I think what you really want is its tryLock method:
Lock lock = new ReentrantLock();
......
if (lock.tryLock())
{
// Got the lock
try
{
// Process record
}
finally
{
// Make sure to unlock so that we don't cause a deadlock
lock.unlock();
}
}
else
{
// Someone else had the lock, abort
}
You can also call tryLock with an amount of time to wait - so you could try to acquire it for a tenth of a second, then abort if you can't get it (for example).
(I think it's a pity that the Java API doesn't - as far as I'm aware - provide the same functionality for the "built-in" locking, as the Monitor class does in .NET. Then again, there are plenty of other things I dislike in both platforms when it comes to threading - every object potentially having a monitor, for example!)
Take a look at the Lock objects introduced in the Java 5 concurrency packages.
e.g.
Lock lock = new ReentrantLock()
if (lock.tryLock()) {
try {
// do stuff using the lock...
}
finally {
lock.unlock();
}
}
...
The ReentrantLock object is essentially doing the same thing as the traditional synchronized mechanism, but with more functionality.
EDIT: As Jon has noted, the isLocked() method tells you at that instant, and thereafter that information is out of date. The tryLock() method will give more reliable operation (note you can use this with a timeout as well)
EDIT #2: Example now includes tryLock()/unlock() for clarity.
I found this, we can use Thread.holdsLock(Object obj) to check if an object is locked:
Returns true if and only if the current thread holds the monitor lock on the specified object.
Note that Thread.holdsLock() returns false if the lock is held by something and the calling thread isn't the thread that holds the lock.
Whilst the above approach using a Lock object is the best way to do it, if you have to be able to check for locking using a monitor, it can be done. However, it does come with a health warning as the technique isn't portable to non Oracle Java VMs and it may break in future VM versions as it isn't a supported public API.
Here is how to do it:
private static sun.misc.Unsafe getUnsafe() {
try {
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void doSomething() {
Object record = new Object();
sun.misc.Unsafe unsafe = getUnsafe();
if (unsafe.tryMonitorEnter(record)) {
try {
// record is locked - perform operations on it
} finally {
unsafe.monitorExit(record);
}
} else {
// could not lock record
}
}
My advice would be to use this approach only if you cannot refactor your code to use java.util.concurrent Lock objects for this and if you are running on an Oracle VM.
While the Lock answers are very good, I thought I'd post an alternative using a different data structure. Essentially, your various threads want to know which records are locked and which aren't. One way to do this is to keep track of the locked records and make sure that data structure has the right atomic operations for adding records to the locked set.
I will use CopyOnWriteArrayList as an example because it's less "magic" for illustration. CopyOnWriteArraySet is a more appropriate structure. If you have lots and lots of records locked at the same time on average then there may be performance implications with these implementations. A properly synchronized HashSet would work too and locks are brief.
Basically, usage code would look like this:
CopyOnWriteArrayList<Record> lockedRecords = ....
...
if (!lockedRecords.addIfAbsent(record))
return; // didn't get the lock, record is already locked
try {
// Do the record stuff
}
finally {
lockedRecords.remove(record);
}
It keeps you from having to manage a lock per record and provides a single place should clearing all locks be necessary for some reason. On the other hand, if you ever have more than a handful of records then a real HashSet with synchronization may do better since the add/remove look-ups will be O(1) instead of linear.
Just a different way of looking at things. Just depends on what your actual threading requirements are. Personally, I would use a Collections.synchronizedSet( new HashSet() ) because it will be really fast... the only implication is that threads may yield when they otherwise wouldn't have.
Another workaround is (in case of you didnt have chance with the answers given here )is using timeouts. i.e. below one will return null after 1 second hanging:
ExecutorService executor = Executors.newSingleThreadExecutor();
//create a callable for the thread
Future<String> futureTask = executor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return myObject.getSomething();
}
});
try {
return futureTask.get(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
//object is already locked check exception type
return null;
}
I needed to also find a solution to this, so searched the Java Concurrency API and came across StampedLock. The project is using Java 8.
I am working in a heavily-threaded asynchronous data service that communicates with a native library and contains long-living configuration objects, necessitating sometimes-complex concurrency logic; thankfully this turned out to be relatively simple with the StampedLock class.
StampedLock has a method called tryOptimisticRead which does not wait, it just returns the status in the form of a long-time time stamp, where zero (0) indicates an exclusive lock is held. I then do delay for up to a second but you could just use the function without any sort of delay.
Here's how I'm detecting whether or not there's an exclusive lock, this paradigm is used in multiple locations and includes error handling:
int delayCount = 0;
//Makes sure that if there is data being written to this field at
// this moment, wait until the operation is finished writing the
// updated data.
while (data1StampedLock.tryOptimisticRead() == 0)
{
try
{
delay(WRITE_LOCK_SHORT_DELAY);
delayCount += 1;
}
catch (InterruptedException e)
{
logError("Interrupted while waiting for the write lock to be
released!", e);
Thread.currentThread().interrupt();
//There may be an issue with the JVM if this occurs, treat
// it like we might crash and try to release the write lock.
data1StampedLock.tryUnlockWrite();
break;
}
if (delayCount * WRITE_LOCK_SHORT_DELAY > TimeUnit.SECONDS.toMillis(1))
{
logWarningWithAlert("Something is holding a write lock on" +
" the data for a very, very long time (>1s). This may" +
" indicate a problem that could cause cascading" +
" problems in the near future." +
" Also, the value for the data that is about to be" +
" retrieved could potentially be invalid.");
break;
}
}
long nonExclusiveLockStamp = data1StampedLock.readLock();
Data data1NonVolatile = data1;
data1StampedLock.unlockRead(nonExclusiveLockStamp);
return data1NonVolatile;
The read locks on a StampedLock are non-exclusive and are like reading from a thread-safe Map or HashTable, where it is multi-read/single-write.
Here is how I am using the exclusive lock to communicate to other threads that the instance data is being written to:
long d1LockStamp = data1StampedLock.writeLock();
this.data1 = data1;
data1StampedLock.unlockWrite(d1LockStamp);
So if you wanted to only check whether or not something is locked at any given moment, you need only something simple like the following statement to get the status:
boolean data1IsLocked = data1StampedLock.tryOptimisticRead() == 0;
Then check the value of that boolean.
There are, of course, the caveats and Here Be Dragons information mentioned in other answers (namely that the information is immediately stale), but if you really need to lock something and check that lock from another thread, this seemed to me to be the most reasonable, safe, and effective way that uses the java.util.concurrency package with no external dependencies.
Thanks for this, it helped me out solving a race condition. I changed it a little to wear both belt and suspenders.
So here is my suggestion for AN IMPROVEMENT of the accepted answer:
You can ensure that you get safe access to the tryLock() method by doing something like this:
Lock localLock = new ReentrantLock();
private void threadSafeCall() {
boolean isUnlocked = false;
synchronized(localLock) {
isUnlocked = localLock.tryLock();
}
if (isUnlocked) {
try {
rawCall();
}
finally {
localLock.unlock();
}
} else {
LOGGER.log(Level.INFO, "THANKS! - SAVED FROM DOUBLE CALL!");
}
}
This would avoid the situation where you might get two calling tryLock() at the almost same time, causing the return to be potentially doubt full. I'd like to now if I'm wrong, I might be over cautios here. But hey! My gig is stable now :-)..
Read more on my development issues at my Blog.

Java ExecutorService:- Notify a thread to wake up when an event occurs

I have a Manager class to which multiple threads register themselves (used UUID to generate unique identifiers per requests), gives payload to process and get their corresponding responses from the manager. I am using java.util.concurrent.ExecutorService to launch multiple threads. Here is an implementation for testing my Manager functionality-
public class ManagerTest {
public static void main(String[] args) {
try {
Manager myManager = new Manager();
// Start listening to the messages from different threads
myManager.consumeMessages();
int num_threads = Integer.parseInt(args[0]);
ExecutorService executor = Executors.newFixedThreadPool(num_threads);
for (int i = 0; i < num_threads; i++) {
// class implementation is given below
Runnable worker = new MyRunnable(myManager);
executor.execute(worker);
}
executor.shutdown();
// Wait until all threads are finish
while (!executor.isTerminated()) {
}
System.out.println("\nFinished all threads");
myManager.closeConnection();
} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
}
}
Here is the implementation of MyRunnable class
class MyRunnable implements Runnable {
private Manager managerObj;
public MyRunnable(Manager managerObj) {
this.managerObj = managerObj;
}
#Override
public void run() {
try {
Random rand = new Random();
int n = rand.nextInt(35);
String requestId = UUID.randomUUID().toString();
managerObj.registerRequest(requestId, n);
managerObj.publishMessage(requestId);
// Want to avoid this while loop
while( ! managerObj.getRequestStatus(requestId)){
}
int response = managerObj.getRequestResponse(requestId);
// do something else
managerObj.unregisterRequest(requestId);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The manager will process requests and depending on the payload the response of a request can take varying amount of time. Whenever manager gets the response it sets the requests status to true by calling this function setRequestStatus(requestId). After this the thread will exit from the while loop and continues its execution.
The code if working fine, but the thread is doing too much work then needed by continuously looping over the while loop until the condition is met.
Is their a way to make a thread sleep after sending the requests to the manager, and manager signals this thread to wake up when its response is ready.
Pardon me if this sounds too simple to someone, I am a newbie to java and java-threading interface.
That's fine, we are used to simple questions, and your question is actually well written and has a reasonable problem to solve, we see a lot worse here every day, like people not knowing what they want, how to ask for it, etc.
So, what you are doing is a busy-spin-loop, and it is a very bad thing to do, because a) it consumes a full CPU core per thread, and b) it actually keeps the CPU busy, which means that it is stealing processing time from other threads that might have useful work to do.
There is a number of ways you can solve this, I will list them from worst to best.
The simplest way to improve your code is to invoke the java.lang.Thread.sleep(long millis) method, passing it 0 as a parameter. This is also known as a "yield" operation, and it essentially means "if there are any other threads that have some useful work to do, let them run, and return back to me once they are done." This is only marginally better than busy-spin-looping because it will still consume 100% CPU. The benefit is that it will only consume CPU while other threads do not have anything to do, so at least it will not slow other things down.
The next best, but still not very smart, way to improve your code is by invoking the java.lang.Thread.sleep(long millis) method passing it 1 as a parameter. This is known as a "pass" operation, and it essentially means "release the remainder of my time-slice to any other threads that might have some useful work to do". In other words, the remainder of the time-slice is forfeited, even if no useful work needs to be done in the entire system. This will bring CPU consumption down to almost zero. The disadvantages are that a) the CPU consumption will actually be slightly above zero, b) the machine will not be able to go to some low-power sleep mode, and c) your worker thread will be slightly less responsive: it will pick up work to do only on a timeslice boundary.
The best way to solve your problem is by using the synchronization mechanism built into java, as explained in this answer: https://stackoverflow.com/a/5999146/773113 This will not only consume zero CPU, but it will even allow the machine to go into a low power mode while waiting.
To solve your problem for the most general case, where you don't want to just wait until a condition, but to actually also pass information about the work that has been done or work which is to be done, you would use a BlockingQueue. (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html) The blocking queue works using the java built-in synchronization mechanism and allows one thread to pass information to another.
There's already a great answer by #MikeNakis, but I feel inclined to offer another option as well.
This option however involves changing the Manager API to return a Future.
The changes to Manager I would propose are these :
drop the getRequestStatus() method
make getRequestResponse() return Future<Integer>
with these changes in place MyRunnable's run() method can change to :
public void run() {
try {
Random rand = new Random();
int n = rand.nextInt(35);
String requestId = UUID.randomUUID().toString();
managerObj.registerRequest(requestId, n);
managerObj.publishMessage(requestId);
// Future.get() blocks and waits for the result without consuming CPU
int response = managerObj.getRequestResponse(requestId).get();
// do something else
managerObj.unregisterRequest(requestId);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
The easiest way to implement the Future<> will likely be using Java's java.util.concurrent.FutureTask.

try-lock to a synchronized statement [duplicate]

I have a process A that contains a table in memory with a set of records (recordA, recordB, etc...)
Now, this process can launch many threads that affect the records, and sometimes we can have 2 threads trying to access the same record - this situation must be denied. Specifically if a record is LOCKED by one thread I want the other thread to abort (I do not want to BLOCK or WAIT).
Currently I do something like this:
synchronized(record)
{
performOperation(record);
}
But this is causing me problems ... because while Process1 is performing the operation, if Process2 comes in it blocks/waits on the synchronized statement and when Process1 is finished it performs the operation. Instead I want something like this:
if (record is locked)
return;
synchronized(record)
{
performOperation(record);
}
Any clues on how this can be accomplished?
Any help would be much appreciated.
Thanks,
One thing to note is that the instant you receive such information, it's stale. In other words, you could be told that no-one has the lock, but then when you try to acquire it, you block because another thread took out the lock between the check and you trying to acquire it.
Brian is right to point at Lock, but I think what you really want is its tryLock method:
Lock lock = new ReentrantLock();
......
if (lock.tryLock())
{
// Got the lock
try
{
// Process record
}
finally
{
// Make sure to unlock so that we don't cause a deadlock
lock.unlock();
}
}
else
{
// Someone else had the lock, abort
}
You can also call tryLock with an amount of time to wait - so you could try to acquire it for a tenth of a second, then abort if you can't get it (for example).
(I think it's a pity that the Java API doesn't - as far as I'm aware - provide the same functionality for the "built-in" locking, as the Monitor class does in .NET. Then again, there are plenty of other things I dislike in both platforms when it comes to threading - every object potentially having a monitor, for example!)
Take a look at the Lock objects introduced in the Java 5 concurrency packages.
e.g.
Lock lock = new ReentrantLock()
if (lock.tryLock()) {
try {
// do stuff using the lock...
}
finally {
lock.unlock();
}
}
...
The ReentrantLock object is essentially doing the same thing as the traditional synchronized mechanism, but with more functionality.
EDIT: As Jon has noted, the isLocked() method tells you at that instant, and thereafter that information is out of date. The tryLock() method will give more reliable operation (note you can use this with a timeout as well)
EDIT #2: Example now includes tryLock()/unlock() for clarity.
I found this, we can use Thread.holdsLock(Object obj) to check if an object is locked:
Returns true if and only if the current thread holds the monitor lock on the specified object.
Note that Thread.holdsLock() returns false if the lock is held by something and the calling thread isn't the thread that holds the lock.
Whilst the above approach using a Lock object is the best way to do it, if you have to be able to check for locking using a monitor, it can be done. However, it does come with a health warning as the technique isn't portable to non Oracle Java VMs and it may break in future VM versions as it isn't a supported public API.
Here is how to do it:
private static sun.misc.Unsafe getUnsafe() {
try {
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void doSomething() {
Object record = new Object();
sun.misc.Unsafe unsafe = getUnsafe();
if (unsafe.tryMonitorEnter(record)) {
try {
// record is locked - perform operations on it
} finally {
unsafe.monitorExit(record);
}
} else {
// could not lock record
}
}
My advice would be to use this approach only if you cannot refactor your code to use java.util.concurrent Lock objects for this and if you are running on an Oracle VM.
While the Lock answers are very good, I thought I'd post an alternative using a different data structure. Essentially, your various threads want to know which records are locked and which aren't. One way to do this is to keep track of the locked records and make sure that data structure has the right atomic operations for adding records to the locked set.
I will use CopyOnWriteArrayList as an example because it's less "magic" for illustration. CopyOnWriteArraySet is a more appropriate structure. If you have lots and lots of records locked at the same time on average then there may be performance implications with these implementations. A properly synchronized HashSet would work too and locks are brief.
Basically, usage code would look like this:
CopyOnWriteArrayList<Record> lockedRecords = ....
...
if (!lockedRecords.addIfAbsent(record))
return; // didn't get the lock, record is already locked
try {
// Do the record stuff
}
finally {
lockedRecords.remove(record);
}
It keeps you from having to manage a lock per record and provides a single place should clearing all locks be necessary for some reason. On the other hand, if you ever have more than a handful of records then a real HashSet with synchronization may do better since the add/remove look-ups will be O(1) instead of linear.
Just a different way of looking at things. Just depends on what your actual threading requirements are. Personally, I would use a Collections.synchronizedSet( new HashSet() ) because it will be really fast... the only implication is that threads may yield when they otherwise wouldn't have.
Another workaround is (in case of you didnt have chance with the answers given here )is using timeouts. i.e. below one will return null after 1 second hanging:
ExecutorService executor = Executors.newSingleThreadExecutor();
//create a callable for the thread
Future<String> futureTask = executor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return myObject.getSomething();
}
});
try {
return futureTask.get(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
//object is already locked check exception type
return null;
}
I needed to also find a solution to this, so searched the Java Concurrency API and came across StampedLock. The project is using Java 8.
I am working in a heavily-threaded asynchronous data service that communicates with a native library and contains long-living configuration objects, necessitating sometimes-complex concurrency logic; thankfully this turned out to be relatively simple with the StampedLock class.
StampedLock has a method called tryOptimisticRead which does not wait, it just returns the status in the form of a long-time time stamp, where zero (0) indicates an exclusive lock is held. I then do delay for up to a second but you could just use the function without any sort of delay.
Here's how I'm detecting whether or not there's an exclusive lock, this paradigm is used in multiple locations and includes error handling:
int delayCount = 0;
//Makes sure that if there is data being written to this field at
// this moment, wait until the operation is finished writing the
// updated data.
while (data1StampedLock.tryOptimisticRead() == 0)
{
try
{
delay(WRITE_LOCK_SHORT_DELAY);
delayCount += 1;
}
catch (InterruptedException e)
{
logError("Interrupted while waiting for the write lock to be
released!", e);
Thread.currentThread().interrupt();
//There may be an issue with the JVM if this occurs, treat
// it like we might crash and try to release the write lock.
data1StampedLock.tryUnlockWrite();
break;
}
if (delayCount * WRITE_LOCK_SHORT_DELAY > TimeUnit.SECONDS.toMillis(1))
{
logWarningWithAlert("Something is holding a write lock on" +
" the data for a very, very long time (>1s). This may" +
" indicate a problem that could cause cascading" +
" problems in the near future." +
" Also, the value for the data that is about to be" +
" retrieved could potentially be invalid.");
break;
}
}
long nonExclusiveLockStamp = data1StampedLock.readLock();
Data data1NonVolatile = data1;
data1StampedLock.unlockRead(nonExclusiveLockStamp);
return data1NonVolatile;
The read locks on a StampedLock are non-exclusive and are like reading from a thread-safe Map or HashTable, where it is multi-read/single-write.
Here is how I am using the exclusive lock to communicate to other threads that the instance data is being written to:
long d1LockStamp = data1StampedLock.writeLock();
this.data1 = data1;
data1StampedLock.unlockWrite(d1LockStamp);
So if you wanted to only check whether or not something is locked at any given moment, you need only something simple like the following statement to get the status:
boolean data1IsLocked = data1StampedLock.tryOptimisticRead() == 0;
Then check the value of that boolean.
There are, of course, the caveats and Here Be Dragons information mentioned in other answers (namely that the information is immediately stale), but if you really need to lock something and check that lock from another thread, this seemed to me to be the most reasonable, safe, and effective way that uses the java.util.concurrency package with no external dependencies.
Thanks for this, it helped me out solving a race condition. I changed it a little to wear both belt and suspenders.
So here is my suggestion for AN IMPROVEMENT of the accepted answer:
You can ensure that you get safe access to the tryLock() method by doing something like this:
Lock localLock = new ReentrantLock();
private void threadSafeCall() {
boolean isUnlocked = false;
synchronized(localLock) {
isUnlocked = localLock.tryLock();
}
if (isUnlocked) {
try {
rawCall();
}
finally {
localLock.unlock();
}
} else {
LOGGER.log(Level.INFO, "THANKS! - SAVED FROM DOUBLE CALL!");
}
}
This would avoid the situation where you might get two calling tryLock() at the almost same time, causing the return to be potentially doubt full. I'd like to now if I'm wrong, I might be over cautios here. But hey! My gig is stable now :-)..
Read more on my development issues at my Blog.

Is there really a race condition in this multi-threaded java code?

I saw a snippet of code in this question which I could not understand (most probably due to the fact am a beginner in this area). The question talks about "an obvious race condition where sometimes the producer will finish, signal it, and the ConsumerWorkers will stop BEFORE consuming everything in the queue."
In my understanding, "isRunning" will be set on the consumers only after the producer decides not to add anymore items in the queue. So, if a consumer thread sees isRunning as FALSE AND then sees inputQueue is empty, then there is NO possibility of anything more getting added into the queue in the future.
Obviosuly, I am wrong and missing something, as no one who responded to that question said the scenario of the question is impossible. So, Can someone pls explain what sequence of events causes this race condition ?
In fact, I see a problem with something else. For ex, if multiple consumer threads saw that the producer isRunning, and say the queue had ONE item, many threads could enter the blocked 'take'. If the producer STOPS now, while one thread would come out of the 'take',
the other threads are blocked on the 'take' forever. Interestingly, no one who answered the question pointed out this problem as well. So, my understanding of this is also probably faulty ?!
I didnt want to add this as a comment there in that question, as it is an old question and my doubt may never get answered !
I am copy/placing the code from that question here for quick reference.
public class ConsumerWorker implements Runnable{
private BlockingQueue<Produced> inputQueue;
private volatile boolean isRunning = true;
public ConsumerWorker(BlockingQueue<Produced> inputQueue) {
this.inputQueue = inputQueue;
}
#Override
public void run() {
//worker loop keeps taking en element from the queue as long as the producer is still running or as
//long as the queue is not empty:
while(isRunning || !inputQueue.isEmpty()) {
System.out.println("Consumer "+Thread.currentThread().getName()+" START");
try {
Object queueElement = inputQueue.take();
//process queueElement
} catch (Exception e) {
e.printStackTrace();
}
}
}
//this is used to signal from the main thread that he producer has finished adding stuff to the queue
public void setRunning(boolean isRunning) {
this.isRunning = isRunning;
}
I think OP of the original question probably meant
while(isRunning && !inputQueue.isEmpty())
rather than
while(isRunning || !inputQueue.isEmpty())
The former clearly produces the issue described by the original poster (*), while the later does indeed have the problem you described in your second point. A simple oversight there, but now we can note that both approaches are incorrect.
(*) and somehow assumes that the queue will never be empty.
You are correct in both questions. Yes && is correct and || is not. As for the second question, answers was to use poison pill or timeout, both ways resolving the problem.
As for me, I would create new synchronization class which aggregates both the queue and isRunning variable, so that changing isRunning causes an exception in take() thus signalling the end of work.

killing an infinite loop in java

I am using a third-party library to process a large number of data sets. The process very occasionally goes into an infinite loop (or is blocked - don't know why and can't get into the code). I'd like to kill this after a set time and continue to the next case. A simple example is:
for (Object data : dataList) {
Object result = TheirLibrary.processData(data);
store(result);
}
processData normally takes 1 second max. I'd like to set a timer which kills processData() after , say, 10 seconds
EDIT
I would appreciate a code snippet (I am not practiced in using Threads). The Executor approach looks useful but I don't quite know how to start. Also the pseudocode for the more conventional approach is too general for me to code.
#Steven Schlansker - suggests that unless the thirdparty app anticipates the interrupt it won't work. Again detail and examples would be appreciated
EDIT
I got the precise solution I was wanting from my colleagues Sam Adams, which I am appending as an answer. It has more detail than the other answers, but I will give them both a vote. I'll mark Sam's as the approved answer
One of the ExecutorService.invokeAll(...) methods takes a timeout argument. Create a single Callable that calls the library, and wrap it in a List as an argument to that method. The Future returned indicate how it went.
(Note: untested by me)
Put the call to the library in another thread and kill this thread after a timeout. That way you could also proces multiple objects at the same time if they are not dependant to each other.
EDIT: Democode request
This is pseudo code so you have to improve and extend it. Also error checking weather a call was succesful or not will be of help.
for (Object data : dataList) {
Thread t = new LibThread(data);
// store the thread somewhere with an id
// tid and starting time tstart
// threads
t.start();
}
while(!all threads finished)
{
for (Thread t : threads)
{
// get start time of thread
// and check the timeout
if (runtime > timeout)
{
t.stop();
}
}
}
class LibThread extends Thread {
Object data;
public TextThread(Object data)
{
this.data = data;
}
public void processData()
{
Object result = TheirLibrary.processData(data);
store(result);
}
}
Sam Adams sent me the following answer, which is my accepted one
Thread thread = new Thread(myRunnableCode);
thread.start();
thread.join(timeoutMs);
if (thread.isAlive()) {
thread.interrupt();
}
and myRunnableCode regularly checks Thread.isInterrupted(), and exits cleanly if this returns true.
Alternatively you can do:
Thread thread = new Thread(myRunnableCode);
thread.start();
thread.join(timeoutMs);
if (thread.isAlive()) {
thread.stop();
}
But this method has been deprecated since it is DANGEROUS.
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html#stop()
"This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack). If any of the objects previously protected by these monitors were in an inconsistent state, the damaged objects become visible to other threads, potentially resulting in arbitrary behavior."
I've implemented the second and it does what I want at present.

Categories

Resources