I've got stuck in this question about multiple producers-consumers question. My goal is to write six threads to act as A, B,...,F, and let the program keep printing forever.
Please click here for the image:click
Each pair of nodes associated with an arrow correspond to a producers-consumers pair (or say buffer). The buffer size is 2 and initially, only A is in possession of 2 tokens.
I've already tried A -> B -> D ->F. The code is as below:
class Cookies
{
private int cookiesNo;
private int buffer=0;
public synchronized void put (int cNo, String sender, String receiver)
{
while (buffer==2)
{
try
{
wait();
}
catch (InterruptedException e){}
}
System.out.println(sender+" put the "+cNo+"th cookie to "+receiver);
cookiesNo= cNo;
buffer++;
notify();
}
public synchronized void eat (int cNo, String sender, String receiver)
{
while (buffer==0)
{
try {
wait();
}
catch (InterruptedException e){}
}
System.out.println(sender+" put the "+cNo+"th cookie to "+receiver);
cookiesNo= cNo;
buffer--;
notify();
}
}
class DPut implements Runnable
{
Cookies cookies;
DPut(Cookies cookies)
{
this.cookies=cookies;
}
public void run()
{
for (int i=1; i<=10000; i++)
{
cookies.put(i, "D", "F");
}
}
}
class DEat implements Runnable //human
{
Cookies cookies;
DEat(Cookies cookies)
{
this.cookies=cookies;
}
public void run()
{
for (int i=1; i<=10000; i++)
{
cookies.eat(i, "B", "D");
}
}
}
class APut implements Runnable
{
Cookies cookies;
APut(Cookies cookies)
{
this.cookies=cookies;
}
public void run()
{
for (int i=1; i<=100; i++)
{
cookies.put(i, "A", "B");
}
}
}
public class practice
{
public static void main(String[] args)
{
Cookies cookies= new Cookies();
DPut dput= new DPut(cookies);
DEat deat= new DEat(cookies);
APut aput= new APut(cookies);
Thread ddog= new Thread(deat);
Thread dmaster= new Thread(dput);
Thread amaster= new Thread(aput);
amaster.start();
ddog.start();
dmaster.start();
}
}
Output(I screenshot the beginning and the middle):
click1 click2
I tried to think it as master(producer), dog(consumer) and cookie(product). The master puts the cookie and the dog eats it.
My problems are:
The output looks like the first picture(AtoB & BtoD) in the beginning 100 cookies. Then it turned to picture two (BtoD & DtoF) until 10 thousand. How can I fix that? I want it to get AtoB running too, but it just stopped...
I don't know how to start on A and F, since they have two ins or two outs.
Is my strategy right? I wrote the code based on the single producer-consumer scenario.
I'm new to multi-threading so please tell me my mistakes.
Thank you so much!
First of all, although 'synchronized' is still valid for mutex, it is 15 years obsolete for signalling. If you want to do wait/notify, use reentrant locks and conditions await/signal[All].
Notify() only wakes 1 thread, and that maybe well be the wrong thread because you don't have any condition for the signal. The last put thread setting the buffer to 2 (full) might notify another put thread, then no more notify occurs to wake a eater.
The old way would be to use notifyAll(), and that would work although would wake up everyone and cause a lot of contention to acquire the synchronized for nothing except for one or two thread. That's why you should prefer reentrant lock with 2 conditions (not empty/notfull).
It's pretty much the basics behind an arrayblockingqueue.
Related
Trying to use n number of threads, where there are two different types of thread that needs to be being swapped between. So goes t1, x1, t2, x2, t3, x3.... where x and t are thread classes. I've been trying to use wait and notify but cant seem to get this to work. Or synchronisation.
All threads all need to access and modify the same list-array in their respective "turns" which i thought could be its own synchronised class, yet maybe an atomic variable would work also?
Any help is very appreciated.
"""
public String startGame(int threadNumbers, List<String> result, String fileLoc) throws IOException {
Players[] playerThreads = new Players[threadNumbers];
Card[] cardThreads = new Card[threadNumbers];
cardDeck cardD = new cardDeck(fileLoc);
for (int i = 0; i < (threadNumbers); i++) {
System.out.println(i);
playerThreads[i] = new Players(i+1, cardD);
if (i>0) {
playerThreads[i-1].next = cardThreads[i-0];
}
if (i==threadNumbers-1) {
playerThreads[i].next = cardThreads[0];
}
cardThreads[i] = new Card(i+1);
if (i>0) {
cardThreads[i-1].next = playerThreads[i-0];
}
if (i==threadNumbers-1) {
cardThreads[i].next = playerThreads[0];
}
new Thread(playerThreads[i]).start();
new Thread(cardThreads[i]).start();
Thread.yield();
Thread.yield();
}
synchronized (playerThreads[0]) {
playerThreads[0].notify();
"""
This is not working, but what needs to happen is they take a card from the deck in a looping way then start the game after they have a hand. The card threads also are just hands but are different as they dont "play" but just work.
Since this seems to be all in one (JVM) process, there's no need for multiple threading here: Just use a queue to track whose turn it is and who's turn it is next. After a player's turn, add them back to the end of the queue.
And actually, now that I think about it there's no reason this same solution couldn't work with multiple processes or over sockets.
Just use a queue
-- Edit --
So what you need is a class with a blocking method. For example
public class Player implements Runnable {
private Move nextMove;
public Move synchronized getMove() {
if (!nextMove) {
this.wait([add timeout if appropriate]);
}
Move next = nextMove;
nextMove = null;
return next;
}
public void run() {
while (true) {
Thread.sleep([someRandomTime]);
synchronized(this) {
if (nextMove == null) {
nextMove = new Move();
this.notify();
}
}
}
}
}
So still using your queue, you go through each Player and call getMove(), which will block until the player posts a move.
BTW, this kind of blocking is similar to how InputStream.read(buffer) works in sockets. The thread calling read waits until the other side of the stream sends some content.
-- Edit 2 --
And just as a reminder: Don't use synchronized, wait, notify or notifyAll on a Thread object.
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 am new to concurrent programming and I am facing few issues with the below code using Java threads.
Status Class (this class tracks the position availability):
public class Status {
private static Map<String, Boolean> positions = new HashMap<>();
static {
//Initially all positions are free (so set to true)
positions.put("A", true);
positions.put("B", true);
}
public synchronized void occupyOrClear(String position,
boolean status) {
positions.put(position, status);
}
public boolean isClear(String position) {
return positions.get(position);
}
}
MyThread Class:
public class MyThread implements Runnable {
private String[] positions;
private String customer;
public MyThread(String customer, String[] positions) {
this.positions = positions;
this.customer = customer;
}
private Status status = new Status();
public void run() {
for (int i = 0; i < positions.length;) {
String position = positions[i];
if (status.isClear(position)) {
// position occupied now
status.occupyOrClear(position, false);
System.out.println(position + " occupied by :"+customer);
try {
//my real application logic goes below (instead of sleep)
Thread.sleep(2000);
} catch (InterruptedException inteExe) {
System.out.println(" Thread interrupted ");
}
// Now clear the position
status.occupyOrClear(position, true);
System.out.println(position + " finished & cleared by:"+customer);
i++;
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException inteExe) {
System.out.println(" Thread interrupted ");
}
}
}
}
}
ThreadTest Class:
public class ThreadTest {
public static void main(String[] args) {
String[] positions = { "A", "B"};
Status status = new Status();
Thread customerThread1 = new Thread(new MyThread(status, "customer1", positions));
Thread customerThread2 = new Thread(new MyThread(status, "customer2", positions));
Thread customerThread3 = new Thread(new MyThread(status, "customer3", positions));
customerThread1.start();
customerThread2.start();
customerThread3.start();
}
}
Even though I have used 'synchronized' I could notice that some times Thread3 is picking up prior to Thread2 and could you please help me to resolve this issue and to acheive the following results ?
(1) Always customerThread1 should take the positions first and then
followed by customerThread2 and then customerThread3 (etc...)
(2) As soon as the A's position is freed by customerThread1, the
position should be immediately picked up by customerThread2 (rather
than customerThread2 and customerThread3 waiting till all positions
are done by customerThread1).And as soon as customerThread2 finishes
position 'A', then customerThread3 should pick it up, etc..
(3) As soon as the position (A, B, etc..) is freed/available, the next
customerThread should pick it up immediately.
(4) The solution should avoid all race conditions
There are several fundamental problems.
You have broken code and already noticed that it doesn’t work. But instead of asking how to fix that broken code, you are asking for alternatives with higher performance. You will never manage to write working programs with that attitude.
Apparently, you have no idea, what synchronized does. It acquires a lock on a particular object instance which can be held by one thread only. Therefore, all code fragments synchronizing on the same object are enforced to be executed ordered, with the necessary memory visibility. So your code fails for two reasons:
You are creating multiple instances of Status accessing the same objects referenced by a static variable. Since all threads use different locks, this access is entirely unsafe.
Your occupyOrClear is declared synchronized, but your method isClear is not. So even if all threads were using the same lock instance for occupyOrClear, the result of isClear remained unpredictable due to its unsafe access to the map.
You have code of the form
if(status.isClear(position)) { status.occupyOrClear(position, false); …
which matches the check-then-act anti-pattern. Even if each of these two method calls were thread-safe, this sequence still remained unsafe, because between these two invocations, everything can happen, most notably, the condition, the thread just checked, may change without the thread noticing. So two or more threads could invoke isClear, receiving true and then proceed with occupyOrClear.
You are using Thread.sleep.
You can try with the following pseudocode:
main() {
//some concurrent queues, eg ConcurrentLinkedQueue
Queue t1Tasks = new Queue("A","B","C");
Queue t2Tasks = new Queue();
Queue t3Tasks = new Queue();
Thread t1 = new PThread(t1Tasks,t2Tasks,"customer1");
Thread t2 = new PThread(t2Tasks,t3Tasks,"customer2");
Thread t3 = new PThread(t3Tasks,null,"customer3");
}
PThread {
Queue q1,q2;
PThread(Queue q1, Queue q2,...){}
run() {
while (item = q1.get()) {
//process item
q2.put(item); //to be processed by next thread
}
}
}
In the below code I have implemented inter Thread communication using wait() -notify() and it is giving me expected output.
expected Output : 123456789 Actual output : 123456789
My question is , is there any guarantee that always 'Main Thread' will get the first chance to execute, since Thread scheduling depends on jvm. And if 'child thread' gets the first chance, the notify() signal will miss and the 'main Thread ' will wait forever. How can I confirm that 'Main thread' will execute first always. Also please confirm if the below code can be improved.
package com.test.Thread;
public class ThreadExample1 {
public static void main(String[] args) throws InterruptedException{
ThreadChild1 lockingObj = new ThreadChild1();
lockingObj .start();
synchronized(lockingObj ){
for(int i=1;i<10;i++){
System.out.println("Main "+i);
}
lockingObj.wait();
System.out.println("Main got notified");
}
}
}
class ThreadChild1 extends Thread{
public void run(){
synchronized(this){
for(int i=1;i<10;i++){
System.out.println("Child "+i);
}
this.notify();
}
}
}
Your code is wrong for the reason that you mentioned yourself: you can't be sure which thread goes first.
There are other things that could go wrong - wait can wake up without a notify.
You can read about it in the Javadoc for the wait method, which also explains what you should do:
As in the one argument version, interrupts and spurious wakeups are
possible, and this method should always be used in a loop:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
In your code, you can solve it with a boolean variable that expresses the condition "I was notified":
public class ThreadExample1 {
public static void main(String[] args) throws InterruptedException {
ThreadChild1 lockingObj = new ThreadChild1();
lockingObj.start();
synchronized (lockingObj) {
for(int i = 1; i < 10; i++) {
System.out.println("Main " + i);
}
while (!lockingObj.haveNotified) {
lockingObj.wait();
}
System.out.println("Main got notified");
}
}
}
class ThreadChild1 extends Thread{
private boolean haveNotified;
public void run(){
synchronized (this) {
for (int i = 1; i < 10; i++) {
System.out.println("Child " + i);
}
haveNotified = true;
this.notify();
}
}
}
While this works correctly on your system, it is not a guranty as your suspicion might become true on a different system. Threading behavior is verry difficult/impossible to predict. Therefore I like to think in worst case scenarios, and if I can come up with a possible breaking situation (as you just described one) I simply redesign to make sure it will work.
A nice trick to test your code is to suspend/pause threads on critical moments by either adding a breakpoint in your IDE, adding a verry time consuming task/call if possible (not failsafe), or by fysically pausing the thread(not always ideal). Besides Im sure there is are libraries to expand on this type of tesing.
I hope this helps you a bit in the right direction.
I've a program that's as follows below. I want three concurrent threads to add different Strings to infiList ("This", "is", "infinite") using thread synchronization.
I want to append certain threads also, for example;
If the last word in infiList is currently “This”, the thread should append word “is” to infiList.
If the last word in infiList is currently “is”, the thread should append word “infinite” to infiList.
If the last word in infiList is currently “infinite”, or if infiList is still empty, the thread should append word “This” to infiList.
At any time, infiList should contain “This” only at the beginning of the list or directly after an occurrence of “infinite”, “is” should occur in the list only directly after a “This”, and an “infinite” should
occur only directly after an “is”.
Any help as to how to do this is appreciated.
import java.util.ArrayList;
public class Multithreading implements Runnable {
public static ArrayList<String> infiList = new ArrayList<>();
#Override
public void run() {
for (int i=0; i<100; i++) {
String s = null;
synchronized (infiList) {
if(infiList.isEmpty())
infiList.add("This");
else
{
s = infiList.get(infiList.size()-1);
if(s.equals("This"))
infiList.add("is");
else if(s.equals("is"))
infiList.add("infinite");
else if(s.equals("infinite"))
infiList.add("This");
}
}
}
}
public static void main (String args[]) {
// Create three concurrent threads
new Thread(new Multithreading()).start();
new Thread(new Multithreading()).start();
new Thread(new Multithreading()).start();
}
}
Very naive quick fix for the problem. Synchronized will obtain a lock, on the arraylist, check the element and insert it based on your rules. But due to your logic being depending on the last element while adding a element to the array while maintaning the order of the elements this is actually not multithreaded but a sequential program.
This is simply because, when multithreaded programs run, you don't care abount the sequentioning, because you can never guarentee it. In most cases you will go into a Divide and Conqueer style algorithm, where the algorithm will be split up into pieces and calculated in pieces.
#Override
public void run() {
for(int i = 0; i < 100; i++) {
String s = null;
synchronized (infiList) {
if(infiList.isEmpty())
infiList.add("This");
else
{
s = infiList.get(infiList.size()-1);
if(s.equals("This"))
infiList.add("is");
else if(s.equals("is"))
infiList.add("infinite");
else if(s.equals("infinite"))
infiList.add("This");
}
}
}
}
How to utilize multithreading
If we look at your example in another case, where you needed to calculate something before you put it into the array. This could lead to utilzing the multithreading performance better.
#Override
public void run() {
while (true) {
String s = null;
CalculateSomethingBig();
synchronized (infiList) {
...
}
}
}
If we play with the thought, that the primary runtime lies within CalculateSomethingBig(), this will now utilize more of the computers multitasking capabilities, because more of the threads will use time to calculate and utilize processing power then to wait on a lock being released.
How to get output
public static void main(String args[]) {
// Create three concurrent threads
new Thread(new Multithreading()).start();
new Thread(new Multithreading()).start();
new Thread(new Multithreading()).start();
for(String s : infiList)
System.out.println(s);
}