java - 子线程的join方法阻塞主线程,如果在另一个子线程中notify那个子线程,会报监视器状态异常,为什么?
PHPz
PHPz 2017-04-17 17:58:34
0
1
816

一.问题
当主线程调用子线程的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次执行!

PHPz
PHPz

学习是最好的投资!

membalas semua(1)
伊谢尔伦

Mari kita bincangkan dahulu mengapa ia tidak boleh "dibangunkan", notify tidak akan "dibangunkan" MyThread3, kerana bukankah menyekat misi kaedah join? Selain itu, MyThread3 tidak tidur. Bukankah ia sentiasa melaksanakan?

Akhir sekali, mari kita lihat pelaksanaan kaedah join, yang mungkin membantu pemahaman anda:

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;
        }
    }
}

Mari kita bincangkan mengapa terdapat pengecualian. Ini sebenarnya agak jelas. Lihat ulasan:

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

Apabila urutan semasa bukan pemilik monitor objek, cuba memanggil kaedah wait atau notify akan melaporkan ralat ini Untuk menyelesaikan pengecualian, dapatkan sahaja kaedah biasa:

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失效");
    }
}
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan