I have a small question for you.
I have two threads:
HelloThread
- This prints "hello" five times.GoodbyeThread
- This prints "Goodbye" five times.I would like the HelloThread
run first and after it's done the GoodbyeThread
run.
I have already solve this problem with semaphore (but semaphore doesn't really true java way, it's more C way).
HelloThread.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package modifiedthreadhellogoodbye;
import static java.lang.Thread.sleep;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.Semaphore;
class HelloThread implements Runnable {
private final Object lock;
//private final Semaphore lock;
public HelloThread(Semaphore lock) {
this.lock = lock;
}
public HelloThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
int pause;
synchronized (lock) {
for (int i = 0; i < 5; i++) {
System.out.println("Hello!");
pause = (int) (Math.random() * 1000);
try {
sleep(pause);
} catch (InterruptedException ex) {
Logger.getLogger(HelloThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
lock.notifyAll();
System.out.println("Outsite hello");
}
//lock.release();
}
}
GoodbyeThread.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package modifiedthreadhellogoodbye;
import static java.lang.Thread.sleep;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
class GoodbyeThread implements Runnable {
int pause;
//private final Semaphore lock;
private final Object lock;
public GoodbyeThread(Semaphore lock) {
this.lock = lock;
}
public GoodbyeThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
System.out.println("Inside the synchronized");
try {
lock.wait();
} catch (InterruptedException ex) {
Logger.getLogger(GoodbyeThread.class.getName()).log(Level.SEVERE, null, ex);
}
//lock.acquire();
for (int i = 0; i < 5; i++) {
System.out.println("Goodbye");
pause = (int) (Math.random() * 1000);
try {
sleep(pause);
} catch (InterruptedException ex) {
Logger.getLogger(GoodbyeThread.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
and this is my class who run thread :
public class ModifiedThreadObject {
private final Object lock = new Object();
//private final Semaphore lock = new Semaphore(0);
public ModifiedThreadObject() {
HelloThread hello = new HelloThread(lock);
GoodbyeThread goodbye = new GoodbyeThread(lock);
Thread t1 = new Thread(hello);
Thread t2 = new Thread(goodbye);
t1.start();
t2.start();
}
}
The main idea is GoodbyeThread
should wait()
for the signal from HelloThread
.
If GoodbyeThread
is run first, it's work perfectly, but HelloThread
runs first I have the following output:
Hello!
Hello!
Hello!
Hello!
Hello!
Outsite hello
Inside the synchronized
HelloThread
sends a notifyAll()
, but nobody is waiting so the "signal" is lost ...
Anybody have an idea?
Firstly, I'd question the use of separate threads at all here. If you want one thing to happen after another, just use a single thread.
However, it's easy to wait until one thread has finished - just use join
:
Thread t1 = new Thread(hello);
Thread t2 = new Thread(goodbye);
t1.start();
t1.join();
t2.start();
That way you don't need any synchronization within the "hello" or "goodbye" code.
If you want anything more complicated, I'd recommend looking in the java.util.concurrent
package. While you can use wait()
and notify()
, it's generally a better idea to use higher-level constructs. For example, for a producer/consumer scenario, you may well want to use BlockingQueue
rather than implement it all yourself.
See more on this question at Stackoverflow