I am new to java programming and trying threading for the first time. I have created a thread to print the even numbers, and then a thread to print odd numbers. In the odd number thread there is a suspend() method after the number 11 to be printed. And after that there is another block to print odd numbers from 13 to 21. In main() I joined the 2 threads. In main function first I called thread t1(even number) and then joined it with thread t2(odd number). As there is suspend it will suspend the output after printing 11 it pauses there. But after that when i call t2.resume() that doesn't continue printing 13 to 21. Why it isn't printing the rest? and how can I make it resume?
Here's the code, please take a look:
class Hi extends Thread {
public void run(){
try{
for(int i=0; i<=10; i ){
System.out.println("1st: " (2*i));
sleep(100);
}
} catch(Exception e){
System.out.println(e);
}
}
}
class Hello extends Thread {
public void run(){
try {
for(int i=0; i<=5; i ){
System.out.println("2nd: " (2*i 1));
}
suspend();
System.out.println(" Resumes again");
for(int i=6; i<=10; i ){
System.out.println("2nd: " (2*i 1));
}
} catch(Exception e){
System.out.println(e);
}
}
}
public class thread {
public static void main(String args[]){
Hi t1 = new Hi();
Hello t2 = new Hello();
t1.start();
try {
t1.join();
} catch (Exception e) {
}
t2.start();
t2.resume();
}
}
OUTPUT:
1st: 0
1st: 2
1st: 4
1st: 6
1st: 8
1st: 10
1st: 12
1st: 14
1st: 16
1st: 18
1st: 20
Exception in thread "main" 2nd: 1
java.lang.IllegalThreadStateException
2nd: 3
2nd: 5
2nd: 7
2nd: 9
2nd: 11
at java.base/java.lang.Thread.start(Thread.java:791)
at thread.main(thread.java:57)
After this the program isn't exiting, I have to exit the program manually (ctrl c) in the terminal.
CodePudding user response:
After this the program isn't exiting, I have to exit the program manually (ctrl c) in the terminal.
Aside from the fact that you should not be using suspend()
and resume()
, I believe your problem is a classic race condition. The main thread is calling t2.start()
and then t2.resume()
but the thread is not suspended yet. The main thread throws an exception and then the t2
thread finishes its printing and calls suspend()
. There is no one left to resume it so the thread never finishes and you have to control-c your program.
You should make a couple of change to your example code. First off use wait/notify instead of suspend()
. For example, have the Hello
thread do:
// t2 thread shouldn't use suspend which is deprecated for good reason
synchronized (this) {
wait();
}
Then in the main thread you need to loop until the thread is in a wait state before notify-ing it. Something like:
while (true) {
if (t2.getState() == State.WAITING) {
synchronized (t2) {
t2.notify();
}
break;
}
Thread.sleep(100);
}
These sorts of thread exercises where one thread is locked stepped with another (aside from a join()
at the end) are a bad example of threading IMO.
Couple other comments. You should join()
with the Hello
thread at the end of your code, never catch Exception
if you can help it since it hides exceptions that may be the source of problems (at least print them as @GhostCat recommended), and also always re-interrupt your threads when you catch InterruptedException
:
try {
t2.join();
} catch (InterruptedException e) {
// always a good pattern
Thread.currentThread().interrupt();
e.printStackTrace();
}
CodePudding user response:
when i call
t2.resume()
that doesn't continue printing 13 to 21. Why it isn't printing the rest?
@Gray answered that one. TLDR: Your main thread calls t2.resume()
before your t2
thread calls suspend()
.
I am curious to know what Java version you are using. I'm running JDK11 on macOS, and I can't get your program to throw that java.lang.IllegalThreadStateException
, but I'm guessing that in whatever JDK and OS you are using, the exception is thrown when your main thread tries to resume()
a thread that isn't suspended.
how can I make it resume?
I would use a Semaphore
.
Let the t2
thread wait to acquire()
a "permit" from a semaphore, and let the main thread release()
a permit to the semaphore at the appropriate time.
I changed your program by replacing the suspend()
call with sem.acquire()
, and by replacing the resume()
call with sem.release()
. I also threw a call to Thread.sleep()
into the main thread before it releases the semaphore so that you can see the pause. Here's the whole thing:
import java.util.concurrent.Semaphore;
class Hi extends Thread { // This class is exactly the same as yours.
public void run(){
try{
for(int i=0; i<=10; i ){
System.out.println("1st: " (2*i));
sleep(100);
}
} catch(Exception e){
System.out.println(e);
}
}
}
class Hello extends Thread {
private Semaphore sem; // new member variable
public Hello(Semaphore sem) { // new constructor to set the new member.
this.sem = sem;
}
public void run(){
try {
for(int i=0; i<=5; i ){
System.out.println("2nd: " (2*i 1));
}
// Wait to "acquire" a permit from the semaphore. This won't
// return until the main thread "releases" a permit _to_ the
// semaphore.
sem.acquire();
System.out.println(" Resumes again");
for(int i=6; i<=10; i ){
System.out.println("2nd: " (2*i 1));
}
} catch(Exception e){
System.out.println(e);
}
}
}
public class Wonk {
public static void main(String args[]){
// Create a semaphore that initially has 0 "permits."
Semaphore s = new Semaphore(0);
Hi t1 = new Hi();
Hello t2 = new Hello(s);
t1.start();
try {
t1.join();
} catch (Exception e) {
}
t2.start();
waitabit(5000); // Sleep 5 seconds, and then...
s.release(); // ...Release the Hounds!!
}
private static void waitabit(int numMilliseconds) {
try {
Thread.sleep(numMilliseconds);
}
catch (Exception e) {
e.printStackTrace();
}
}
}