一.问题
当主线程调用子线程的join方法时,其实还是调用子线程的wait方法来阻塞主线程,那么有两个问题:
a.如果我在另一个子线程中获得当前子线程对象,并调用线程的notify方法,是不是可以解除子线程的阻塞,经测试会报监视器状态异常。
b.子线程是个单独的对象,为啥会阻塞主线程呢?又不存在共享资源竞争,尤其是Thread中join方法是个普通的synchronized方法
二、代码
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
MyThread3 thread=new MyThread3();
NotifyThread nt=new NotifyThread(thread);
thread.start();
nt.start();
thread.join();
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName() + "线程第" + i + "次执行!");
}
}
}
class NotifyThread extends Thread{
Thread myThread ;
public NotifyThread(Thread myThread){
this.myThread=myThread;
}
public void run(){
try {
System.out.println("休眠开始");
Thread.sleep(3000);
System.out.println("休眠结束");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myThread.notify();
System.out.println("已唤醒,让Join失效");
}
}
class MyThread3 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
System.out.println(this.getName() + "线程第" + i + "次执行!");
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
三、异常
Thread-0线程第0次执行!
休眠开始
Thread-0线程第1次执行!
Thread-0线程第2次执行!
休眠结束
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at thread.com.simple.NotifyThread.run(JoinTest.java:29)
Thread-0线程第3次执行!
Thread-0线程第4次执行!
Thread-0线程第5次执行!
Thread-0线程第6次执行!
Thread-0线程第7次执行!
Thread-0线程第8次执行!
Thread-0线程第9次执行!
main线程第0次执行!
main线程第1次执行!
main线程第2次执行!
伊谢尔伦2017-04-17 18:00:34
Let’s talk about why it can’t be “awakened” first. notify
不会“唤醒”MyThread3
,因为阻塞不就是join
方法的使命么?再说MyThread3
There is no sleep mode. Isn’t it always executing? Why is there such a thing as “awakened”?
Finally, let’s take a look at the implementation of the join
method, which may be helpful to your understanding:
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
Let’s talk about why there is an exception. It’s actually quite clear. See the comments:
/**
* Thrown to indicate that a thread has attempted to wait on an
* object's monitor or to notify other threads waiting on an object's
* monitor without owning the specified monitor.
*/
When the current thread is not the owner of the object monitor, trying to call its wait
或者notify
method will report this error. To solve the exception, just get the owner. Common methods:
public class NotifyThread extends Thread{
Thread myThread ;
public NotifyThread(Thread myThread){
this.myThread=myThread;
}
public void run(){
try {
System.out.println("休眠开始");
Thread.sleep(3000);
System.out.println("休眠结束");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(myThread){
myThread.notify();
}
System.out.println("已唤醒,让Join失效");
}
}