public static void main(String[] args){
final Business b = new Business();
new Thread(){
@Override
public void run(){
for(int i=1; i<=50; i++){
b.sub(i);
}
}
}.start();
for(int i=1; i<=50; i++){
b.main(i);
}
}
class Business{
private boolean bShouldSub = true;
public synchronized void main(int i){
while(bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=1; j<=100; j++){
System.out.println(Thread.currentThread().getName() + ", loop times: " + j + " of " + i);
}
bShouldSub = true;
this.notify();
}
public synchronized void sub(int i){
while(!bShouldSub){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int j=1; j<=10; j++){
System.out.println(Thread.currentThread().getName() + ", loop times: " + j + " of " + i);
}
bShouldSub = false;
this.notify();
}
}
注意:在wait一定放在while循环里,不要用if来判断条件,防止假唤醒(比如interrupt或者timeout),参见wait方法的jdk描述:
-
A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:
synchronized (obj) { while (<condition does not hold>) obj.wait(timeout); ... // Perform action appropriate to condition }
(For more information on this topic, see Section 3.2.3 in Doug Lea's "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, 2000), or Item 50 in Joshua Bloch's "Effective Java Programming Language Guide" (Addison-Wesley, 2001).