Reputation: 11
I am implementing a simple multi-threading example,in which Thread 1 prints PING after every 1000ms and Thread 2 prints PONG after every 2000ms.
public class T extends Thread
{
public void run()
{
int i =10;
while(i>0)
{
if(Thread.currentThread().getName().equals("T1"))
{
System.out.println("\nPING");
try {Thread.sleep(1000);}
catch (InterruptedException e) {e.printStackTrace();}
}
else if (Thread.currentThread().getName().equals("T2"))
{
System.out.println("\nPONG");
try {Thread.sleep(2000);}
catch (InterruptedException e) {e.printStackTrace();}
}
i--;
}
}
public static void main(String[] args)
{
Thread t1 = new T();
Thread t2 = new T();
t1.setName("T1");
t2.setName("T2");
t1.start();
t2.start();
}
}
But the output is like ::
PONG
PING
PING
PING
PONG
PING
PING
PONG
PING
PING
PONG
PING
PING
PONG
PING
PONG
PONG
PONG
PONG
PONG
But my expected output should be like
PING
PING
PONG
PING
PING
PONG
PING
PING
PONG.....
What changes should be made in the code ?
Upvotes: 1
Views: 2085
Reputation: 28727
Move the
System.out.println("\nPING or PONG");
after the Thread.sleep()
not before.
or add a Thread.sleep() between the treads when you start them.
t1.start();
Thread.sleep(100);
t2.start();
(But I don't like the second solution)
Altough this is not a professional solution, it should work for about 30 iterations. Later, since they are not proper synchronized this does not work anymore.
Upvotes: 0
Reputation: 16035
From documentation of Thread.sleep:
Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.
If you want to make sure the thread printing PING is run twice and then waits for the other thread to print PONG (and it in turn waits for two PINGS before proceeding), you need to synchronize the threads with each other. See Object.wait and Object.notify.
Edit: here's a version with synchronization (it's messy, but so is the original in the question ;P):
public class T extends Thread
{
//Static object to synchronize on... bad practice but this is just an example anyway
static Object synchOnMe = new Object();
public void run()
{
int i = 10;
while(i > 0)
{
if(Thread.currentThread().getName().equals("T1"))
{
System.out.println("PING");
try
{
Thread.sleep(1000);
//Synchronize on every second time (ie. wait for PONG)
if((i + 1) % 2 == 0)
{
synchronized(synchOnMe)
{
synchOnMe.notify();
synchOnMe.wait();
}
}
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
else if(Thread.currentThread().getName().equals("T2"))
{
try
{
//Synchronize every time (ie. wait for PING)
synchronized(synchOnMe)
{
synchOnMe.wait();
System.out.println("PONG");
synchOnMe.notify();
}
Thread.sleep(2000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
i--;
}
//One last notify to release the other thread waiting
synchronized(synchOnMe)
{
synchOnMe.notify();
}
}
public static void main(String[] args)
{
Thread t1 = new T();
Thread t2 = new T();
t1.setName("T1");
t2.setName("T2");
t1.start();
t2.start();
}
}
Output:
PING
PING
PONG
PING
PING
PONG
PING
PING
PONG
PING
PING
PONG
PING
PING
PONG
Upvotes: 2
Reputation: 273
First, you should use a for loop instead of a while loop. It makes your intent much more clear. Second, you need to understand that threads are not guaranteed to execute in the order you start them in. All that's guaranteed is that the kernel will start allocating timeslices to the thread according to how the underlying operating system works and that the kernel will wait at minimum the amount of time you specify for the thread to sleep (sometimes it will be even less, if the kernel supports coalesced threads).
This means that T1 could in reality wait for 996 ms on a round and T2 could wait 2026 ms for another. When I ran this code, for example, I got the following output:
PING
PONG
PING
PING
PONG
PING
PING
PONG
PING
PONG
PING
PING
PONG
PING
PING
PONG
PONG
PONG
PONG
PONG
A bit of a mess. Now, in many multithreaded applications this is okay when the threads are not dependent on each other. If you want your output to line up the way you expect, though, then like the other answers suggest, you need to use wait() and notify().
For example, have T1 start, then have T1 start T2. T2 should wait immediately on execution, then T1 should notify T2 each time it PINGs. T2 can then count how many times it's received a notify and whenever the count is even, it can output a PONG.
I leave the implementation open as an exercise.
Upvotes: 0
Reputation: 489
In general this is not possible to have deterministic output (unless you ise some fancy real time technologies) in such case. It is due to the way how OS manages threads. The fact that thread has ended spleeping does not mean that it will receive CPU time immediately.
The only way to have deterministic ordering of thread execution is to use synchronization between them. Use google to learn more as this is pretty complicated matter.
Upvotes: 0
Reputation: 279960
Say both threads start at time 0 and for whatever (thread scheduling) reason PONG
starts first.
PONG (now wait 2000) // 0 has elapsed
PING (now wait 1000) // 0 has elapsed
PING (now wait 1000) // 1000 has elapsed
PING (now wait 1000) // 2000 has elapsed
PONG (now wait 2000) // 2000 has elasped
... and so on
If you want to PING
s and then one PONG
, consider using some notification mechanism (semaphore, coutdown latches, etc.). Don't rely on sleep()
.
Upvotes: 4
Reputation: 16060
I would use a ThreadPool from the newer concurrent package:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool(int)
Upvotes: 0