为了账号安全,请及时绑定邮箱和手机立即绑定

子线程的join方法阻塞主线程,如果在另一个子线程中notify那个子线程,会报监视器状态异常

子线程的join方法阻塞主线程,如果在另一个子线程中notify那个子线程,会报监视器状态异常

动漫人物 2019-03-12 09:15:59
一.问题当主线程调用子线程的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 {@Overridepublic 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.IllegalMonitorStateExceptionat 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次执行!
查看完整描述

1 回答

?
湖上湖

TA贡献2003条经验 获得超2个赞

先谈为什么“唤醒”不了,notify不会“唤醒”MyThread3,因为阻塞不就是join方法的使命么?再说MyThread3也没有休眠,不是一直在执行么,何来“唤醒”之说!


最后来看看join方法的实现,或许对你理解有帮助:


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;

        }

    }

}

再来谈为什么有异常,其实已经比较明确了,看注释:


/**

 * 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.

 */

当前线程不是该对象monitor所有者时,试图调用其wait或者notify方法就会报这个错,解决异常只要拿到所有者就好了,常见方法:


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失效");

    }

}


查看完整回答
反对 回复 2019-04-19
  • 1 回答
  • 0 关注
  • 499 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信