I am completely new to multi threading. Need assistance on the below scenario
Scenario:- I want two threads to execute, such that they have to print the word "PingPong" alternatively. This has to happen three 3 times for both threads.
For example:-
Thread 1 has to print "Ping" and it has to go to wait stage.
Thread 2 has to print "Ping" and it has to go to wait stage as well as notify the other thread.
Thread 1 has to print "Pong" and it has to go to wait stage as well as notify the other thread.
Thread 2 has to print "Pong" and it has to go to wait stage as well as notify the other thread.
The same way both the threads has to print the word 3 times in total.
Coding below:-
package com.test.files;
public class MultiThreadingTest2 implements Runnable {
String lastExecutedThread = "";
Object lockObj = new Object();
private void print(String wordToPrint) throws InterruptedException {
synchronized(lockObj) {
if(lastExecutedThread.equals(Thread.currentThread().getName())) {
System.out.println(Thread.currentThread().getName()+" entered wait stage");
lockObj.wait();
} else {
lastExecutedThread = Thread.currentThread().getName();
System.out.println(Thread.currentThread().getName()+" printed "+wordToPrint);
lockObj.notifyAll();
}
}
}
public MultiThreadingTest2(Object lock) {
this.lockObj = lock;
}
#Override
public void run() {
String[] wordArr = {"Ping", "Pong"};
for(int i = 0; i < 3; i++) {
for(int j = 0; j < wordArr.length; j++) {
try {
print(wordArr[j]);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Thread t1 = new Thread(new MultiThreadingTest2(lock), "Thread 1");
Thread t2 = new Thread(new MultiThreadingTest2(lock), "Thread 2");
t1.start();
t2.start();
}
}
But I could see the above code has resulted in deadlock. Output as follow:-
Thread 1 printed Ping
Thread 1 entered wait stage
Thread 2 printed Ping
Thread 2 entered wait stage
Thread 1 entered wait stage
I am not sure why this has resulted in deadlock. Reason because, the variable "lastExecutedThread " is created at class level. So it should be stored in heap. If its a local variable, then we can say that it could be in thread stack, so the other thread may not what value it possess and because of which the thread executing the print function will have the "lastExecutedThread" to its name and it will lead to deadlock.
Could you please help on this.
You have to make lastExecutedThread static, otherwise each Thread sees its own instance of it.
Note that if inside the print method lockObj.wait() is called, the wordToPrint passed to this method is never printed. You can slightly adapt your code to avoid this: if your print method returns true if printing was successful, and false otherwise. Then inside your nested for-loop, put your call of print inside a while-loop: while (!print(wordArr[j]));
Related
I am new to java and I am trying to learn about threads.
I am expecting an output of alternate hello this is thread one and hello this is thread two. but the output I get is as follows:
hello this is thread one
hello this is thread one
hello this is thread one
hello this is thread one
hello this is thread one
hello this is thread two
hello this is thread two
hello this is thread two
hello this is thread two
hello this is thread two
Below is my code. Can anyone please help me out to why I am getting this output as opposed to expected. And what is it that I can do to run the two threads in parallel.
public class ThreadDemo {
public static void main(String args[]) {
// This is the first block of code
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread one");
}
}
};
// This is the second block of code
Thread threadTwo = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread two");
}
}
};
// These two statements are in the main method and begin the two
// threads.
// This is the third block of code
thread.start();
// This is the fourth block of code
threadTwo.start();
}
}
Just because threads may interlace does not mean that they will. Your threads simply run too fast. Try adding Thread.sleep() to make them run longer.
The problem here is that PrintStream is synchronized which is not fair.
final Lock lock = new ReentrantLock(true); //create fair lock
//after running this code change it to
//ReentrantLock(false); to see what happens
// This is the first block of code
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
lock.lock();
System.out.println("hello this is thread one");
lock.unlock();
}
}
};
// This is the second block of code
Thread threadTwo = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
lock.lock();
System.out.println("hello this is thread two");
lock.unlock();
}
}
};
// These two statements are in the main method and begin the two
// threads.
// This is the third block of code
thread.start();
// This is the fourth block of code
threadTwo.start();
when a lock is fair it will be alot slower, but when its not fair as in your first case it keeps grabbing the lock over and over before the other thread gets a chance to take it. A fair lock is like a queue. Whoever is queued to take it next gets it.
Depending on the number of CPUs and/or CPU cores, multi-threading may only be simulated by your CPU by giving each thread a certain number of time before another thread is scheduled. See also Wikipedia on "Preemptive Multitasking"
Also, given today's CPUs and many cores and their speed, it may also be that the execution of the first thread already finished before the second one is started.
Also, both threads are battling for the lock in System.out, so they will lock each other out.
Let the threads run for longer times (higher number of iterations), and you will see the interleaving you are expecting.
Your code would work too..add sleep in the first object.
// This is the first block of code
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread one");
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
If you want to have the threads' bodies wait until both threads are running, you can use something like a CountDownLatch, which can block until its internal counter counts down to zero:
final CountDownLatch latch = new CountDownLatch(2);
Thread thread = new Thread() {
#Override public void run() {
latch.countDown();
latch.await(); // Execution waits here until latch reaches zero.
// Rest of the method.
}
}
Thread threadTwo = new Thread() {
#Override public void run() {
latch.countDown();
latch.await(); // Execution waits here until latch reaches zero.
// Rest of the method.
}
}
thread.start();
threadTwo.start();
(Exception handling omitted for clarity)
This will guarantee that the "interesting bit" of the two threads' run methods will be executing at the same time. However, because of the unfair synchronization on the println() method you are calling, there is no guarantee of how the messages printed by the two threads will be interleaved:
Sometimes they might "perfectly" interleave (1, 2, 1, 2, ...)
Sometimes a few of one might be printed without anything from the other (1, 1, 2, 1, 2, 2, 2, ...)
Sometimes one might print all of its messages before the other (1, 1, 1, 1, 2, 2, 2, 2).
Below code is working...
public class ThreadDemo {
public static void main(String args[]) throws InterruptedException {
// This is the first block of code
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread one");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
// This is the second block of code
Thread threadTwo = new Thread() {
public void run() {
for (int i = 0; i < 10; i += 2) {
System.out.println("hello this is thread two");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadDemo.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
// These two statements are in the main method and begin the two
// threads.
// This is the third block of code
thread.start();
// This is the fourth block of code
threadTwo.start();
}
}
Your code is working as expected, there is absolutely no guarantee that your implementation will execute in the pre-defined manner you are expecting.
I would suggest that you look at other methods of implementing multithreaded code such as join(), sleep() and finding one that better suits your needs.
I am unable to understand that if my variable is both volatile and static then why threads are not reflecting the common shared value in the output
Output of last few lines is :
Thread is running
4998Thread-0
Thread is running
4999Thread-0
Thread is running
4899Thread-1
Thread is running
public class Test implements Runnable{
volatile static int i=0;
#Override
public void run() {
for(;i<5000;i++)
{ try {
Thread t = Thread.currentThread();
String name = t.getName();
// Thread.sleep(10);
System.out.println(i+name);
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("Thread is running");
}}
public static void main(String[] args) {
Test t=new Test();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
// t.run();
t2.start();
}
}
You can't use a compound (multi step) operation like i++ on a volatile variable.
You can have both threads retrieve the value, increase it, and write it back resulting in one lost increment (as you see in your example).
Volatile ensures that changes to the variable are visible to other threads. But it does not ensure synchronization.
From one execution of your program I get this output :
Thread is running
3474Thread-1
Thread is running
3475Thread-0
Thread is running
3477Thread-0
(.... many lines where i goes from 3478 to 4998, with Thread-0 always being the one running...)
Thread is running
4999Thread-0
Thread is running
3476Thread-1
Thread is running
This happens because threads get slices of processor time to be run and their execution can be paused and resumed at any point.
Here Thread-1 is executing line "System.out.println(i+name);" with i having a value of 3476. i+name is evaluated to "3476Thread-1" but just then the Thread-1 execution stops and instead Thread-0 gets its time slice. Thread-0 executes till finalization. And then Thread-1 gets again to execute. We have left it after i+name had been evaluated to "3476Thread-1" and before the call to println. The call is now completed and printed, hence you see "3476Thread-1" at then end. i has been increased to 5000 by Thread-0 but that does not change the result of the evaluation of i+name which was done before all those increases.
The problem is that i++ and i+name are different instructions and thread execution can be paused and resumed between them. To ensure that you get a secuential output you need to ensure than there is no interruption between i++ and i+name. That is, you need to make that set of instructions atomic.
public class Test implements Runnable{
static Object lock = new Object();
volatile static int i=0;
#Override
public void run() {
for(;;)
{
try {
Thread t = Thread.currentThread();
String name = t.getName();
synchronized( lock )
{
if ( i>=5000 )
break;
i++;
System.out.println(i+name);
}
// Thread.sleep(10);
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Thread is running");
}
} }
public static void main(String[] args) {
Test t=new Test();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
// t.run();
t2.start();
}
}
In that program, if Thread-1 gets paused between i++ and i+name it will be inside the a critical section controlled by synchronized(lock). When Thread-0 gets to execute it will reach the synchronized(lock) instruction and will have to stop executing until Thread-1 resumes and gets out of that block. Because the JLS ensures that :
The synchronized statement (ยง14.19) computes a reference to an object;
it then attempts to perform a lock action on that object's monitor and
does not proceed further until the lock action has successfully
completed. After the lock action has been performed, the body of the
synchronized statement is executed. If execution of the body is ever
completed, either normally or abruptly, an unlock action is
automatically performed on that same monitor.
Here's a code snippet I learned usage of volatile keyword from:
import java.util.concurrent.TimeUnit;
public class VolatileDemo {
private volatile static boolean stop; //remove volatile keyword to see the difference
private static int i = 0;
public static void main(String[] args) throws InterruptedException {
Thread otherThread = new Thread(new Runnable() {
public void run() {
while (!stop)
i++;
}
});
otherThread.start();
TimeUnit.SECONDS.sleep(1);
stop = true;// main thread stops here and should stop otherThread as well
}
}
If you want to observe what volatile does, try to remove it and then follow the execution, this should be obvious after you run those two versions, but basically keyword here prevents java compiler from assuming that stop condition never changes, it will be read every time the condition gets evaluated. Neat, isn't it?
By looking at your code the problem isn't with usage of volatile keyword, the problem is that the expression i++ is not atomic. It actually is 3 step operation:
1) fetch value of i;
2) increment i;
3) save new value of i
When multi-threading comes into play, these might or might not be mixed with other thread's instructions.
So the execution might look like that as well:
1) T1: fetch i;
2) T2: fetch i;
3) T1: increment i;
4) T2: increment i;
5) T1: save i;
6) T2: save i;
If i was 0 you thought you will get 2 as the output, and here's 1 instead.
Go with synchronization, which is pretty simple when not overused and well thought.
Suggested read on synchronization
If two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use synchronization in that case to guarantee that the reading and writing of the variable is atomic.
Therefore you need to use synchronization when you modify the i value.
I'm a newbie to synchronization and trying to understand how wait and notify works.
Question:-
The programs executes 2 threads - T1 & T2 simultaneously but based on the output T1 runs first, executes the question(first) method, prints the question, sets the flag(true), runs the notify() method, executes the question(second) method & enters the wait method. Now T2 starts and executes.
Why does T2 doesn't start until T1 calls the wait method of the Object Chat.
When the question method is executed first time and notify() method is called, there is no wait() on the chat object(since t2 did not yet start). so, which thread listens to this notify method.
My codes:
package TestThread;
class Chat {
boolean flag = false;
public synchronized void Question(String msg) {
System.out.println("Question method = " + flag);
if (flag) {
try {
System.out.println("Question method wait start");
wait();
System.out.println("Question method wait finish");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(msg);
flag = true;
notify();
}
public synchronized void Answer(String msg) {
System.out.println("Answer method = " + flag);
if (!flag) {
try {
System.out.println("Answer method wait start");
wait();
System.out.println("Answer method wait finish");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(msg);
flag = false;
notify();
}
}
class T1 implements Runnable {
Chat m;
String[] s1 = { "Hi", "How are you ?", "I am also doing fine!" };
public T1(Chat m1) {
this.m = m1;
new Thread(this, "Question").start();
}
public void run() {
for (int i = 0; i < s1.length; i++) {
m.Question(s1[i]);
}
}
}
class T2 implements Runnable {
Chat m;
String[] s2 = { "Hi", "I am good, what about you?", "Great!" };
public T2(Chat m2) {
this.m = m2;
new Thread(this, "Answer").start();
}
public void run() {
for (int i = 0; i < s2.length; i++) {
m.Answer(s2[i]);
}
}
}
public class MultiThread {
public static void main(String[] args) {
Chat m = new Chat();
new T1(m);
new T2(m);
}
}
Result:-
Question method = false
Hi
Question method = true
Question method wait start
Answer method = true
Hi
Answer method = false
Answer method wait start
Question method wait finish
How are you ?
Question method = true
Question method wait start
Answer method wait finish
I am good, what about you?
Answer method = false
Answer method wait start
Question method wait finish
I am also doing fine!
Answer method wait finish
Great!
Why does T2 doesn't start until T1 calls the wait method of the Object
Chat.
You have a same object 'm' and passed it to different threads and there is method level synchronization , so the moment a 'call' enters the question() there will be lock on whole object till wait() is called Hence answer method will be blocked.
When the question method is executed first time and notify() method is
called, there is no wait() on the chat object(since t2 did not yet
start). so, which thread listens to this notify method.
notify() has no significance for the first time, synchronized method has to finish thats all. as said earlier answer() is not executed till the question() finishes / releases the lock (calling wait())
Why does T2 doesn't start until T1 calls the wait method of the Object Chat?
You've got a race condition. Either of the two threads will execute first. Since they both share a single Chat instance, whose methods are synchronized, one will block until the other has unlocked the monitor on the Chat instance.
When the question method is executed first time and notify() method is
called, there is no wait() on the chat object(since t2 did not yet
start). so, which thread listens to this notify method?
None do.
1.) Why does T2 doesn't start until T1 calls the wait method of the Object Chat?
Actually T2 starts before that but you don't notice because you don't have any logging statements to show up. Put a System.out inside run method of T2 and run your program a few times. You will see T2 starting before T1 calls wait method. Keep in mind T2 cannot enter the Chat object's Answer method since its lock is acquired by T1 before wait() is eventually called.
Another thing to keep in mind is that there is no guarantee of the order in which threads will be started. Just because T1.start appears before T2.start , does not mean T1 will always be started first. Thread scheduler makes that decision.
2.)When the question method is executed first time and notify() method is called, there is no wait() on the chat object(since t2 did not yet start). so, which thread listens to this notify method.
--If there has been no wait calls , then notify won't impact any threads.
in this project I am trying to do some concurrency among threads using semaphores as signaling, however the concurrency is not working at all. I can only use acquire and release and no synchronized keyword methods allowed. I read countless webpages and it says that
// do something
acquire()
release()
//do something
Which I understand but in this program I am trying to test signals with a semaphore between threads, for example user requests deposit and teller should say deposit completed.However my signals(semaphores) are not working as I want to print in order for example
I need to deposit
Deposit is complete
instead I get this
Customer0created
I need to deposit
I have withdrawn <---
Customer0joined from main
Teller0created
You wanna withdrawal? <---- (out of order)
Deposit is complete
Regardless how i reorder them or how much i read the semaphore signaling to comm threads is not working.
[code]import java.util.concurrent.Semaphore;
public class Threads {
private static Semaphore depositTransaction = new Semaphore (1, true);
private static Semaphore withdrawal = new Semaphore (1, true);
public static void main(String[] args)
{
final int customerThreads = 1;
final int tellerThreads = 1;
final int loanThreads = 1;
Customer thr[] = new Customer[customerThreads]; //
Thread cThread[] = new Thread[customerThreads]; //
for (int i= 0; i < customerThreads; i++)
{
thr[i]= new Customer(i);
cThread[i] = new Thread(thr [i]);
cThread[i].start();
}
for ( int i = 0; i < customerThreads; i++ )
{
try {
cThread[i].join();
System.out.println("Customer"+i + "joined from main");
}
catch (InterruptedException e)
{
}
}
Teller thr1[] = new Teller[tellerThreads];
Thread tThread[] = new Thread[tellerThreads];
for (int b = 0; b< tellerThreads; b++)
{
thr1[b] = new Teller(B)/>;
tThread[b]= new Thread(thr1 [b]);
tThread[b].start();
}
}
static class Customer implements Runnable
{
private int customerNumber = 0;
private int balance = 0;
Customer(int cn)
{
this.customerNumber = cn;
balance = 1000;
System.out.println("Customer"+ customerNumber + "created");
}
public void run()
{
try
{
System.out.println("I need to deposit");
depositTransaction.acquire();// signal
}
catch(InterruptedException e)
{
Thread.currentThread().interrupt();
e.printStackTrace();
}
withdrawal.release();
System.out.println("I have withdrawn");
}
}
static class Teller implements Runnable
{
private int tellerNumber = 0;
Teller(int tn)
{
this.tellerNumber = tn;
System.out.println("Teller"+ tellerNumber +"created");
}
public void run()
{
try
{
System.out.println("You wanna withdrawal?");
withdrawal.acquire();
}
catch(InterruptedException e)
{
Thread.currentThread().interrupt();
}
depositTransaction.release();
System.out.println("Deposit is complete");
}
}
}[/code]
Here is a program that uses a semaphore to play ping pong. It is very similar to what you need for your goal. This program has one thread that will print PING, and the other prints PONG. It uses a semaphore to ensure that PING is printed first, then PONG, then PING and so on.
Notice how this program uses two semaphores, and that it starts both semaphores at zero. This means that when the threads call acquire() on it, they will block. You have been using the value of one, which means that neither thread would block and that both would rush ahead.
Now that all threads have blocked, we need to get one of them to start. We send a 'release()' signal to the semaphore that the thread that we want to start up on. That will increment the semaphore by one, and the thread blocked in acquire() will wake up and decrement it again before proceeding with its all important job of printing PING or PONG.
Remember the following about semaphores:
A semaphore contains an integer value (called a permit count)
acquire() will block until the integer value is greater than zero; when greater than zero the count will be decremented by one before exiting
release() never blocks. It only ever increments the integer value by one, and as a side effect wakes up any method that were blocked in a call to acquire().
Thus for a game of ping pong to work: (ascii art below scrolls to the right)
s1=0 -- release() --> s1=1 s1=0
s2=0 s2=0 s2=1
thread1=blocked thread1 runs -- calls s2.release() --> thread1 blocked
thread2=blocked thread2=blocked thread2 runs
Notice how the values of s1 and s2 oscilate between 0 and 1, but we do not allow them both to have the value of 1 at the same time. If they were ever to both equal 1, then both thread1 and thread2 would be able to run at the same time. Which would be known as a race condition, as the order of their execution would be unpredictable.
public class PingPong {
public static void main( String[] args ) throws InterruptedException {
final Semaphore s1 = new Semaphore(0);
final Semaphore s2 = new Semaphore(0);
final AtomicInteger countDown = new AtomicInteger( 10 );
Thread threadA = new Thread() {
public void run() {
try {
System.out.println("threadA started");
while (countDown.get() > 0) {
s1.acquire();
System.out.println( "PING" );
s2.release();
countDown.decrementAndGet();
}
} catch ( InterruptedException e ) {
e.printStackTrace();
}
System.out.println("threadA finished");
}
};
Thread threadB = new Thread() {
public void run() {
try {
System.out.println("threadB started");
while (countDown.get() > 0) {
s2.acquire();
System.out.println( "PONG" );
s1.release();
countDown.decrementAndGet();
}
} catch ( InterruptedException e ) {
e.printStackTrace();
}
System.out.println("threadb finished");
}
};
threadA.start();
threadB.start();
s1.release();
}
}
You are not using semaphores correctly for what you want to do. As I get it, you want to start the customer thread, then block until the teller threads finishes then finish the customer thread.
Right now your semaphore do close to nothing. They will prevent multiple customer threads from running at the same time, but within your acquire / release block, nothing happens.
If you want to synchronize between customer and teller, both classes need to use the same Semaphore
What I would suggest is this :
remove the join operation for now
create the depositTransaction semaphore with count 0, so the first acquire will block.
Start a customer thread
The thread will block waiting for a deposit
Start a teller thread
make the deposit and release the depositTransaction semaphore
the customer thread will unblock
you can now join both threads
Edit :
I don't think that your idea of adding tons of semaphore for every action is a good idea. You will end up with complex locking and deadlocks all over the place. What I would suggest is to limit the number of semaphore and implement messages between the threads. The semaphore will tell the other one (Client tells Teller and vice-versa) to check the messages after pushing one.
Start customer thread
push message that customer is waiting
signal for new customer request
wait for teller signal
Start teller thread
acquire sem for new customer request
check message
do stuff
signal customer that stuff is done
messages will then be "withdrawal customer 0" or any other action you want to implement
Would suggest you to look at one of the standard examples and rework your code. Semaphore is very easy to use and all we need to do is acquire the lock when a thread accesses the shared resource and release the lock when it it is done.
There is nice example with a producer and a consumer thread protecting a shared resource here.
Semaphore Example with a Producer and Consumer thread
I am trying to synchronize three threads to print 012012012012.... but it is not working correctly. Each thread is assigned a number which it prints when it receives a signal from main thread. There is something wrong with the following program which I am not able to catch.
public class Application {
public static void main(String[] args) {
int totalThreads = 3;
Thread[] threads = new Thread[totalThreads];
for (int i = 0; i < threads.length; i++) {
threads[i] = new MyThread(i);
threads[i].start();
}
int threadIndex = 0;
while (true) {
synchronized(threads[threadIndex]) {
threads[threadIndex].notify();
}
threadIndex++;
if (threadIndex == totalThreads) {
threadIndex = 0;
}
}
}
}
class MyThread extends Thread {
private int i;
public MyThread(int i) {
this.i = i;
}
#Override
public void run() {
while (true) {
synchronized(this) {
waitForSignal();
System.out.println(i);
}
}
}
private void waitForSignal() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
You need more coordination. the notify call does not immediately wake up the thread and force it to proceed. Instead, think of notify as sending an email to the thread to let it know that it can proceed. Imagine if you wanted your 3 friends to call you in order. You sent friend 1 an email to call you, waited one second, sent an email to friend 2, waited a second, and sent an email to friend 3. do you think you'd get called in that exact order?
one way to add more coordination would be to have some shared state which indicates whose turn it is. if all your friends could see your house, you could put a number on the outside of the house indicating whose turn it was to call. each friend would wait until they saw their number, and then call.
Here's your problem:
int threadIndex = 0;
while (true) {
synchronized(threads[threadIndex]) {
threads[threadIndex].notify();
}
threadIndex++;
if (threadIndex == totalThreads) {
threadIndex = 0;
}
}
The main thread notifies all threads in the right order. However, your threads are working independently. They may or may not get scheduled at a specific point in time. So the end result may be, that thread 2 is reaching the wait/print lock before thread 1 before thread 0. The final order is not determined by you sending the notifications, but (in essence) by the scheduler.
The solution is to change it this way:
the main thread notifies exactly one thread: thread 0
every thread does his work and when done, notifies the next thread in line
obviously the last thread has to notify thread 0 again.
Another possible solution: In the main thread, you can wait immediately after having notified a thread (in the same synchronized block), like this:
synchronized (threads[threadIndex])
{
threads[threadIndex].notify();
threads[threadIndex].wait(); // try/catch here
}
And in the run method of the thread, you can use notifyAll to wake up the main thread after the thread finished its work:
synchronized (this)
{
waitForSignal();
System.out.println(i);
notifyAll();
}
More sophisticated solutions would involve classes from the java.util.concurrent.locks package.
package threads;
import java.util.concurrent.Semaphore;
public class ZeroEvenOddPrinter {
class Runner extends Thread{
Semaphore prev;
Semaphore next;
int num = 0;
public Runner(Semaphore prev,Semaphore next,int num){
this.prev = prev;
this.next = next;
this.num = num;
}
#Override
public void run(){
while (true) {
try {
Thread.sleep(100);
prev.acquire();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (num == 0)
System.out.println(0);
else {
System.out.println(num);
num = num + 2;
}
next.release();
}
}
}
static public void main(String args[]) throws InterruptedException{
Semaphore sem1 = new Semaphore(1);
Semaphore sem2 = new Semaphore(1);
Semaphore sem3 = new Semaphore(1);
ZeroEvenOddPrinter zeo = new ZeroEvenOddPrinter();
Runner t1 = zeo.new Runner(sem1,sem2,0);
Runner t2 = zeo.new Runner(sem2,sem3,1);
Runner t3 = zeo.new Runner(sem3,sem1,2);
sem1.acquire();
sem2.acquire();
sem3.acquire();
t1.start();
t2.start();
t3.start();
sem1.release();
}
}
Here i am using semaphores as triggers for all the three threads. Initially all threads will be blocked on sem1,sem2,sem3. Then i will release the sem1 and first thread will execute then it will release the second thread and so on... The best part is you extend this logic to n number of threads. Good Luck!!!