Maison > Questions et réponses > le corps du texte
一.问题
当主线程调用子线程的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
Parlons d'abord de la raison pour laquelle il ne peut pas être « réveillé », notify
ne sera pas « réveillé » MyThread3
, car le blocage de la mission de la méthode join
n'est-il pas ? D'ailleurs, MyThread3
ne dort pas, n'est-il pas toujours en train d'exécuter ?
Enfin, jetons un œil à la mise en œuvre de la méthode join
, qui peut être utile à votre compréhension :
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;
}
}
}
Parlons de la raison pour laquelle il y a une exception. C'est en fait assez clair. Voir les commentaires :
/**
* 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.
*/
Lorsque le thread actuel n'est pas le propriétaire du moniteur d'objets, essayer d'appeler sa méthode wait
ou notify
signalera cette erreur. Pour résoudre l'exception, obtenez simplement le propriétaire :
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失效");
}
}