I'm looking at other examples here and in other sites and I'm not understanding what I'm doing wrong. I'm trying to do a program that one thread sets the value of an object to the values 1 to 10, but I want to wait for it to change the value until other thread reads it, so I can print them and have a list from 1 to 10.
My readThread run method just loops from 1 to 10 calling the following method:
private synchronized int receive() {
try {
wait();
int value = this.mainThread.getValor();
notify();
return value;
} catch (InterruptedException e) {
e.printStackTrace();
}
return -1;
}
My writeThread run method just loops from 1 to 10 calling the following method:
private synchronized void send(int n) {
try {
this.mainThread.setValor(n);
notify();
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The main method is the following:
public static void main(String[] args) {
MainThread mt = new MainThread();
ReadThread rt = new ReadThread(mt);
WriteThread wt = new WriteThread(mt);
wt.start();
rt.start();
}
The class MainThead has the property "valor" defined with its getter and setter
Thank you for your help
There are a couple of obvious problems.
It looks as if you are synchronising on the same lock (there isn't enough code to be 100% sure). Generally you should create an object specifically to use as a lock.
send may be executed before receive. In that case the first notify will do nothing, and both threads will stall in wait.
In theory, there is no guarantee that wait will not wakeup spontaneously. For this and other reasons, you really want the wait inside a while loop.
Related
class Q {
int n;
boolean valueSet = false;
synchronized int get() {
while (!valueSet)
try {
wait();
} catch (Exception e) {
}
;
System.out.println("Pego : " + n);
valueSet = false;
notify();
return n;
}
synchronized void put(int n) {
while (valueSet)
try {
wait();
} catch (Exception e) {
}
;
this.n = n;
valueSet = true;
System.out.println("Inserido : " + n);
notify();
}
}
class Producer2 implements Runnable {
Q q;
Producer2(Q q) {
this.q = q;
new Thread(this, "Geradora").start();
}
public void run() {
int i = 0;
while (true) {
q.put(i++);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer2 implements Runnable {
Q q;
Consumer2(Q q) {
this.q = q;
new Thread(this, "Consumidora").start();
}
public void run() {
while (true) {
q.get();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class PCFixed {
public static void main(String[] args) {
Q q = new Q();
new Producer2(q);
new Consumer2(q);
}
}
Text from the book:
Inside get(), wait() is called. This suspends the execution till Producer notify...
My question is, Once I instantiate Producer and Consumer, the execution reaches put, not get. So how come it calls get first and then call wait() inside get()?
The system can only be in one of two states:
It is empty
valueSet is false, the put method will not even once enter that while loop and thus never invokes wait(), and the get method would wait().
It is full
valueSet is true, the get method will not even once enter that while loop and thus never invokes wait(), and the put method would wait().
Explanation
Because the get and put methods are synchronized, only one can be running (and note that wait() will open the gates and let other code run. It'll re-acquire the lock before wait() actually exits - for code to go on past a wait(), both notify() must be called, and whatever called it needs to get to the end of it synchronized block/method.
The code starts off in 'empty' mode.
It doesn't matter if you attempt to invoke put and get simultaneously; these methods are synchronized on the this reference so only one can actually run, the other would freeze until the lock is available. Thus, we have two options:
The put call wins. In this case, the put call will immediately set the value and not wait at all, sets the mode to 'full' (valueSet = true), does a useless notify() that has no effect but also does no harm, and ends. The get call was waiting to start and can now start. It will not wait at all (as it is in "full" mode; valueSet == true), gets the value and prints it, sets the mode back to empty, does another useless notify, and exits.
The get call wins. In this case, the get call will enter the while loop and waits. This releases the lock, which means the put call can now go. It will not wait at all (as the while loop's condition is false, which means it runs zero times), it sets a value, and notify() - that 'releases' the get() call which now merely waits for the lock to be available to continue. The put method ends, thus releasing the lock. The get call continues and fetches the value. It then does a useless notify, and exits as well.
Instead you attempt to run 2 put calls simultaneously. One wins and immediately sets as usual, then the other runs and will immediately enter wait mode and will be stuck there (as will any further put calls, they all run into the wait() call and wait there), until you call get() in some thread, this will get a value, set the thing to be in 'empty' mode, and notifies one arbitrary thread, thus unlocking it. It will put its value and set your object back to "full" mode and exit, leaving the other putters still waiting around. Another get call would immediately proceed, fetch it, notify another one of the waiting put calls, and so on.
Because both Producer2 and Consumer2 create a new thread in their constructors.
So calling
new Producer2(q);
In the main method, doesn't stop the execution, it goes immediately to the next line which is
new Consumer2(q);
Which is where the call to q.get happens
When I first read about interface BlockingQueue I read that: Producer blocks any more put() calls in a queue if it has no more space. And the opposite, it blocks method take(), if there are no items to take. I thought that it internally works same as wait() and notify(). For example, when there are no more elements to read internally wait() is called until Producer adds one more and calls notify()..or that's what we would do in 'old producer/consumer pattern. BUT IT DOESN'T WORK LIKE THAT IN BLOCKING QUEUE. How? What is the point? I am honestly surprised!
I will demonstrate:
public class Testing {
BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3);
synchronized void write() throws InterruptedException {
for (int i = 0; i < 6; i++) {
blockingQueue.put(i);
System.out.println("Added " + i);
Thread.sleep(1000);
}
}
synchronized void read() throws InterruptedException {
for (int i = 0; i < 6; i++) {
System.out.println("Took: " + blockingQueue.take());
Thread.sleep(3000);
}
}
}
class Test1 {
public static void main(String[] args) {
Testing testing = new Testing();
new Thread(new Runnable() {
#Override
public void run() {
try {
testing.write();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
try {
testing.read();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
OUTPUT:
Added 0
Added 1
Added 2
'program hangs'.
My questions is how does take() and put() BLOCK if they don't use wait() or notify() internally? Do they have some while loops that burns CPU circles fast? I am frankly confused.
Here's the current implementation of ArrayBlockingQueue#put:
/**
* Inserts the specified element at the tail of this queue, waiting
* for space to become available if the queue is full.
*
* #throws InterruptedException {#inheritDoc}
* #throws NullPointerException {#inheritDoc}
*/
public void put(E e) throws InterruptedException {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
You'll see that, instead of using wait() and notify(), it invokes notFull.await(); where notFull is a Condition.
The documentation of Condition states the following:
Condition factors out the Object monitor methods (wait, notify and notifyAll) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock implementations. Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.
If you go through below code, you will get an idea that how producer/consumer problem will get resolve using BlokingQueue interface.
Here you are able to see that same queue has been shared by Producer and Consumer.
And from main class you are starting both thread Producer and Consumer.
class Producer implements Runnable {
protected BlockingQueue blockingQueue = null;
public Producer(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
#Override
public void run() {
for (int i = 0; i < 6; i++) {
try {
blockingQueue.put(i);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Added " + i);
}
}
}
class Consumer implements Runnable {
protected BlockingQueue blockingQueue = null;
public Consumer(BlockingQueue blockingQueue) {
this.blockingQueue = blockingQueue;
}
#Override
public void run() {
for (int i = 0; i < 6; i++) {
try {
System.out.println("Took: " + blockingQueue.take());
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Test1 {
public static void main(String[] args) throws InterruptedException {
BlockingQueue queue = new ArrayBlockingQueue(3);
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
new Thread(producer).start();
new Thread(consumer).start();
Thread.sleep(4000);
}
}
This code will print output like
Took: 0
Added 0
Added 1
Added 2
Took: 1
Added 3
Added 4
Took: 2
Added 5
Took: 3
Took: 4
Took: 5
(I'm sure some or all parts of my answer could be something that you have already understood, in that case, please just consider it as a clarification :)).
1. Why did your code example using BlockingQueue get to ‘program hangs’?
1.1 Conceptually
First of all, if we can leave out the implementation level detail such as ‘wait()’, ‘notify()’, etc for a second, conceptually, all implementation in JAVA of BlockingQueue do work to the specification, i.e. like you said:
‘Producer blocks any more put() calls in a queue if it has no more
space. And the opposite, it blocks method take(), if there are no
items to take.’
So, conceptually, the reason that your code example hangs is because
1.1.1.
the thread calling the (synchronized) write() runs first and alone, and not until ‘testing.write()’ returns in this thread, the 2nd thread calling the (synchronized) read() will ever have a chance to run — this is the essence of ‘synchronized’ methods in the same object.
1.1.2.
Now, in your example, conceptually, ‘testing.write()’ will never return, in that for loop, it will ‘put’ the first 3 elements onto the queue and then kinda ‘spin wait’ for the 2nd thread to consume/’take’ some of these elements so it can ‘put’ more, but that will never happen due to aforementioned reason in 1.1.1
1.2 Programmatically
1.2.1.
(For producer) In ArrayBlockingQueue#put, the ‘spin wait’ I mentioned in 1.1.2 took form of
while (count == items.length) notFull.await();
1.2.2.
(For consumer) In ArrayBlockingQueue#take, it calls dequeue(), which in turn calls notFull.signal(), which will end the ‘spin wait’ in 1.2.1
2.Now, back to your original post’s title ‘What is the point of BlockingQueue not being able to work in synchronized Producer/Consumer methods?’.
2.1.
If I take the literal meaning of this question, then an answer could be ‘there are reasons for a convenient BlockingQueue facility to exist in JAVA other than using them in synchronized methods/blocks’, i.e. they can certainly live outside of any ‘synchronized’ structure and facilitate a vanilla producer/consumer implementation.
2.2.
However, if you meant to inquire one step further - Why can’t JAVA BlockQueue implementations work easily/nicely/smoothly in synchronized methods/blocks?
That will be a different question, a valid and interesting one that I am also incidentally puzzling about.
Specifically, see this post for further information (note that in this post, the consumer thread ‘hangs’ because of EMPTY queue and its possession of the exclusive lock, as opposed to your case where the producer thread ‘hangs’ because of FULL queue and its possession of the exclusive lock; but the core of the problems should be the same)
I want to have a thread which does some I/O work when it is interrupted by a main thread and then go back to sleep/wait until the interrupt is called back again.
So, I have come up with an implementation which seems to be not working. The code snippet is below.
Note - Here the flag is a public variable which can be accessed via the thread class which is in the main class
// in the main function this is how I am calling it
if(!flag) {
thread.interrupt()
}
//this is how my thread class is implemented
class IOworkthread extends Thread {
#Override
public void run() {
while(true) {
try {
flag = false;
Thread.sleep(1000);
} catch (InterruptedException e) {
flag = true;
try {
// doing my I/O work
} catch (Exception e1) {
// print the exception message
}
}
}
}
}
In the above snippet, the second try-catch block catches the InterruptedException. This means that both of the first and second try-catch block are catching the interrupt. But I had only called interrupt to happen during the first try-catch block.
Can you please help me with this?
EDIT
If you feel that there can be another solution for my objective, I will be happy to know about it :)
If it's important to respond fast to the flag you could try the following:
class IOworkthread extends Thread {//implements Runnable would be better here, but thats another story
#Override
public void run() {
while(true) {
try {
flag = false;
Thread.sleep(1000);
}
catch (InterruptedException e) {
flag = true;
}
//after the catch block the interrupted state of the thread should be reset and there should be no exceptions here
try {
// doing I/O work
}
catch (Exception e1) {
// print the exception message
// here of course other exceptions could appear but if there is no Thread.sleep() used here there should be no InterruptedException in this block
}
}
}
}
This should do different because in the catch block when the InterruptedException is caught, the interrupted flag of the thread is reset (at the end of the catch block).
It does sound like a producer/consumer construct. You seem to kind of have it the wrong way around, the IO should be driving the algorithm. Since you stay very abstract in what your code actually does, I'll need to stick to that.
So let's say your "distributed algorithm" works on data of type T; that means that it can be described as a Consumer<T> (the method name in this interface is accept(T value)). Since it can run concurrently, you want to create several instances of that; this is usually done using an ExecutorService. The Executors class provides a nice set of factory methods for creating one, let's use Executors.newFixedThreadPool(parallelism).
Your "IO" thread runs to create input for the algorithm, meaning it is a Supplier<T>. We can run it in an Executors.newSingleThreadExecutor().
We connect these two using a BlockingQueue<T>; this is a FIFO collection. The IO thread puts elements in, and the algorithm instances take out the next one that becomes available.
This makes the whole setup look something like this:
void run() {
int parallelism = 4; // or whatever
ExecutorService algorithmExecutor = Executors.newFixedThreadPool(parallelism);
ExecutorService ioExecutor = Executors.newSingleThreadExecutor();
// this queue will accept up to 4 elements
// this might need to be changed depending on performance of each
BlockingQueue<T> queue = new ArrayBlockingQueue<T>(parallelism);
ioExecutor.submit(new IoExecutor(queue));
// take element from queue
T nextElement = getNextElement(queue);
while (nextElement != null) {
algorithmExecutor.submit(() -> new AlgorithmInstance().accept(nextElement));
nextElement = getNextElement(queue);
if (nextElement == null) break;
}
// wait until algorithms have finished running and cleanup
algorithmExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.YEARS);
algorithmExecutor.shutdown();
ioExecutor.shutdown(); // the io thread should have terminated by now already
}
T getNextElement(BlockingQueue<T> queue) {
int timeOut = 1; // adjust depending on your IO
T result = null;
while (true) {
try {
result = queue.poll(timeOut, TimeUnits.SECONDS);
} catch (TimeoutException e) {} // retry indefinetely, we will get a value eventually
}
return result;
}
Now this doesn't actually answer your question because you wanted to know how the IO thread can be notified when it can continue reading data.
This is achieved by the limit to the BlockingQueue<> which will not accept elements after this has been reached, meaning the IO thread can just keep reading and try to put in elements.
abstract class IoExecutor<T> {
private final BlockingQueue<T> queue;
public IoExecutor(BlockingQueue<T> q) { queue = q; }
public void run() {
while (hasMoreData()) {
T data = readData();
// this will block if the queue is full, so IO will pause
queue.put(data);
}
// put null into queue
queue.put(null);
}
protected boolean hasMoreData();
protected abstract T readData();
}
As a result during runtime you should at all time have 4 threads of the algorithm running, as well as (up to) 4 items in the queue waiting for one of the algorithm threads to finish and pick them up.
I am just wondering how to control console inputs in separate threads?
I have thread A and thread B and thread C; B and C they both control user input... the thing is I am not pretty sure how to switch between B and C threads the scanIn.nextLine(); because B seems to loop two unnecessary iterations before thread C can interrupt B :(
Main thread:
public class Main
{
private volatile ThreadGroup threadGroup=new ThreadGroup();//contains concurrent hash map...
private volatile TaskManager taskManager=new TaskManager(threadGroup);
private A a=new A(threadGroup);
private B b=new B(threadGroup,taskManager);
private C c=new C(threadGroup);
Main()
{
b.start();
threadGroup.add(a,"A");
threadGroup.add(b,"B");
threadGroup.add(c,"C");
}
public static void main(String args[]){new Main();}
}
TaskManager method snippet:
...
public synchronized void threadCMaybeCanBeStartedLater()
{
this.getThreadGroup().get("A").start();
}
...
thread A code like a (overridden run method invokes):
public void loopIt()
{
Random generator = new Random();
A: while(!this.interrupted())
{
Thread.sleep(1000);
int i=generator.nextInt(100)+1;
int j=generator.nextInt(100)+1;
if(i==j){this.invokeC(); System.out.println("event : i==j");}
}
}
private void invokeC()
{
if(!this.getThreadGroup().get("C").isAlive())this.getThreadGroup().get("C").start();
}
thread B code like a:
public void loopIt() throws InterruptedException
{
Scanner scanIn = new Scanner(System.in);
B: while(!this.isInterrupted())
{
Thread.sleep(1000);
String command= scanIn.nextLine();
...
if(command.equals("a"))
{
System.out.println("a was entered");
this.getTaskManager().threadCMaybeCanBeStartedLater();//
continue;
}
if(command.equals("b"))
{
System.out.println("b was entered");
continue;
}
if(command.equals("c"))
{
System.out.println("c was entered");
continue;
}
else{System.out.println("no such command");}
}
}
thread C (the run method invokes)
public void loopIt() throws InterruptedException
{
getThreadGroup().get("B").interrupt();
Scanner scanIn = new Scanner(System.in);
C: while(!this.isInterrupted())
{
Thread.sleep(1000);
String command= scanIn.nextLine();
...
if(command.equals("d"))
{
System.out.println("d was entered");
continue;
}
if(command.equals("e"))
{
System.out.println("e was entered");
this.interrupt();
break C;
}
if(command.equals("f"))
{
System.out.println("f was entered");
continue;
}
else{System.out.println("no such command");}
}
getThreadGroup().get("B").start();
}
...as you can see, the major code conception (see A thread snippet) is "you don't know when thread C can be started but when it started you need to give it console"; that's all; if it was GUI there was no problem but console-like app makes it quite problematic...
So the question is ... how to interrupt/re-start thread B immediately from thread C in this case?
Thanks
Synchronising Threads Using Thread Class
Thread.interrupt() on its own does not synchronise logic & timing between two threads.
Thread.interrupt() signals that the caller would like the thread to interrupt at a time in the near future. The interrupt() method sets an interrupt flag. The isInterrupted() method checks whether this flag is set (& also clears the flag again). The methods Thread.sleep(), Thread.join(), Object.wait() and a number of I/O methods also check & clear this flag, when throwing InterruptedException.
The thread doesn't immediately pause but continues running code. The internal thread logic is designed & implemented by the developer: continue to run thread code considered atomic/urgent until it gets to an "interruptable point", then check the interrupted flag / catch InterruptedException & then do a clean pause - usually via Thread.sleep(), Thread.join() or Object.wait(), and sometimes by exiting Thread.run() altogether thus stopping the thread permanently.
While all of this is happening the calling thread is still running and will execute an indeterminate amount of code before the interrupt takes effect... hence the lack of synchronisation. There is a lack of guaranteed happens-before condition between the code in one thread and code in the other thread.
Some approaches that do synchronise logic & timing between two threads (creating a happens-before condition):
thread1 calls Thread2.join()
thread1 calls SomeObject.wait() and thread2 calls SomeObject.notify()
Synchronise on a method or block
Quick Review of Your Code:
Thread B runs in an infinite loop - there is no call to interrupt it from any thread and no call for it's thread to wait(). It will, however, temporily block until System.in has more input, and then continue.
Thread A only interrupts itself - cleaner and easier to analyse logic if you don't call this.interrupt() and while(!this.isInterrupted()): just change the while loop into: do { .... } while (i != j)
Thread A only interrupts itself - cleaner and much easier to analyse logic if you don't call this.interrupt() and while(!this.isInterrupted()): just change the while loop into: do { .... } while (!"e".equals(command))
Thread C must make the following calls at the top of it's while loop:
threadB.interrupt();
synchronized(this) {
try {
this.wait();
} catch (InterruptedException ie) {
}
Thread B must make the following call as the last line of code:
synchronized(threadC) {
threadC.notify();
}
Reading from I/O (nextLine()) is a blocking & interruptable operation. Right next to it you introduce Thread.sleep() which is also a blocking & interruptable operation that introduces an artificial delay in your code - it is not necessary; remove.
The only Scanner method you call is nextLine(). You're using it as if it were an InputStreamReader & not doing any scanning. Also, you're not buffering input. If code stays like this, replace 'Scanner scanIn = Scanner(System.in)' with: 'BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))'.
The only ThreadGroup method you call are add() and get(). You're using it as if it were a HashMap & not doing any thread group management. If code stays like this, you may replace 'ThreadGroup' with 'HashMap'. However, even the HashMap seems excessive - could simply pass Threads references to other Threads using constructors/setters and avoid HashMap altogether.
Avoid excessive use of continue inside loops - try to avoid altogether. Best to do this by chaining successive 'if' statements together using '} else if {'...
Potential race condition between main thread and thread B. When thread B is started (from Main()) it may execute many lines of code before the main thread executes any more code - B may call ThreadGroup.get() before main thread has called ThreadGroup.add() x 3. Solution: in Main(), put b.start() after ThreadGroup.add() x 3
In general, "a".equals(command) is better practice than command.equals("a") - it handles nulls, giving correct result without NPE (you seem lucky here - probably won't have nulls).
Suggested Changes:
public class ThreadA extends Thread {
ThreadC threadC;
public void setThreadC(ThreadC threadC) {
this.threadC = threadC;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
Random generator = new Random();
int i, j;
do {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
}
i=generator.nextInt(100)+1;
j=generator.nextInt(100)+1;
} while (i != j);
threadC.start();
}
}
public class ThreadB extends Thread {
ThreadA threadA;
ThreadC threadC;
public void setThreadA(ThreadA threadA) {
this.threadA = threadA;
}
public void setThreadC(ThreadC threadC) {
this.threadC = threadC;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
// loop until interrupted
try {
while (!this.isInterrupted()) {
command = reader.readLine();
if ("a".equals(command)) {
System.out.println("a was entered");
if (threadA.getState() == Thread.State.NEW) {
threadA.start();
}
} else if ("b".equals(command)) {
System.out.println("b was entered");
} else if ("c".equals(command)) {
System.out.println("c was entered");
} else if ("z".equals(command)) {
System.out.println("z was entered");
throw new InterruptedException("Command z interruption");
} else {
System.out.println("no such command");
}
}
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
}
// Now notify ThreadC - it will wait() until this code is run
synchronized(threadC) {
threadC.notify();
}
}
}
public class ThreadC extends Thread {
ThreadB threadB;
public void setThreadB(ThreadB threadB) {
this.threadB = threadB;
}
#Override
public void run() {
this.loopIt();
}
public void loopIt() {
// Block until the lock can be obtained
// We want thread B to run first, so the lock should be passed into Thread C constructor in an already locked state
threadB.interrupt();
synchronized(this) {
try {
// Put this thread to sleep until threadB calls threadC.notify().
//
// Note: could replace this line with threadB.join() - and remove
// from threadB the call to threadC.notify()
this.wait();
} catch (InterruptedException ie) {
}
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String command = null;
while (!"e".equals(command)) {
try {
command= reader.readLine();
if ("d".equals(command)) {
System.out.println("d was entered");
} else if ("e".equals(command)) {
System.out.println("e was entered");
} else if ("f".equals(command)) {
System.out.println("f was entered");
} else if ("z".equals("command")) {
System.out.println("z was entered");
} else {
System.out.println("no such command");
};
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
}
nextLine() does not respond to interruption. You want to do something like
String command;
if (scanIn.hasNextLine())
command = scanIn.nextLine();
else
Thread.sleep(1000);
You can use flag variables (as global variables) to control the while loop in each thread...
suppose that Thread A has an infinite loop like this
while(true)
while(x == 1){
your code ...
}
Thread.sleep(2000);
}
when Thread b is started you can change x to 0 (suppose x is a global variable) then when Thread b finishes executing change x to 1 at the end of Thread b code...
or you can interrupt the thread from thread itself based of flag value x
I have a homework assignment called "The H2O problem" where I'm supposed to implement a class called H2OBarrier which has 3 methods.
HReady, a method called when a hydrogen atom (thread) is ready
OReady, a method called when an oxygen atom (thread) is ready
makeWater, a method called when 2 hydrogen atoms and one oxygen atom are ready
I'm supposed to do this using Java Reentrant locks and Conditions.
This is my code so far, and I'm wondering if I'm properly using lock and unlock.
public class H2OBarrier {
int hCount;
int oCount;
Lock lock = new ReentrantLock();
Condition hWait = lock.newCondition();
Condition oWait = lock.newCondition();
public void HReady() {
lock.lock();
hCount++;
try {
hWait.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void OReady(){
lock.lock();
oCount++;
try {
while(hCount<2 && oCount<1){
oWait.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
makeWater();
}
}
public void makeWater(){
hCount--;
hWait.signal();
lock.unlock();
hCount--;
hWait.signal();
lock.unlock();
oCount--;
oWait.signal();
lock.unlock();
}
}
Should I be calling unlock() anywhere other than in my makeWater method? The whole flow of the program seems to make pretty logical sense to me, I'd just like to make sure what I'm doing looks correct overall.
Your code is producing a deadlock. Imagine 5 o atoms go through first, 5 go into o queue produced by await(). Now it doesn't matter if 2 h atoms go through, all the h atoms will automatically wait because of your code.