为什么等待线程不会永远等待
Why Waiting Thread Doesn't wait forever
我在下面找到了复制 Java 中的 join() 行为的代码。有两种可能的执行路径:
- 当Main线程继续执行并进入synchronized块时。
然后它必须等待线程 t 完成。
- 当Thread t先启动并调用运行方法时,Main线程等待获取锁。
在这两种情况下,都没有 notify(),但程序仍会以适当的输出完成。你能告诉我为什么主线程没有永远等待,因为没有 notify() 吗?
public class SequentialTreadWithoutJoin {
public static void main(String[] args) {
MyThread t = new MyThread("myThread");
t.start();
synchronized(t){
try {
System.out.println("Before wait");
t.wait();
System.out.println("After wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i = 0; i < 10; i++)
System.out.println("Thread " + Thread.currentThread().getName() + " will continue after join and print : " + i );
}
}
class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
public synchronized void run(){
System.out.println("Thread " + this.getName() + " will run for 1 minute");
try {
this.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
同步块工作
同步是围绕称为内部锁或监视器锁的内部实体构建的。 (API 规范通常将此实体简称为 "monitor.")内在锁在同步的两个方面都发挥作用:强制对对象状态的独占访问和建立对同步至关重要的先行关系能见度。
每个对象都有一个与之关联的内部锁。按照惯例,需要对对象字段进行独占和一致访问的线程必须在访问它们之前获取对象的内部锁,然后在完成访问后释放内部锁。据说线程在获取锁和释放锁之间拥有内部锁。只要一个线程拥有一个内在锁,其他线程就不能获取同一个锁。另一个线程在尝试获取锁时将阻塞。
当线程释放内在锁时,在该操作与同一锁的任何后续获取之间建立了先行关系。
同步方法中的锁
当线程调用同步方法时,它会自动获取该方法对象的内部锁,并在方法 return 时释放它。即使 return 是由未捕获的异常引起的,也会发生锁定释放。
如果没记错的话,你的主线程调用等待线程t,但是wait()只能从线程本身调用。没有人可以调用您的 wait()。所以 t.wait() 是没有用的,因为它不是 t 本身调用的,而是主线程调用的。
t.wait() 应该是 t.join()。在这种情况下,主线程将等待线程 t 完成。此外,整个同步块都可以去,因为它只有一个线程去那里。 t 永远不会到达该代码,因为 t 只运行 MyThread.run().
的代码
所以在 t.start() 之后一个简单的 t.join() 会延迟主线程直到 t 完成。
更新:正如 Augusto 强调的那样,该程序依赖于 JDK 的隐式行为才能正常工作。赞成他的回答。
先来个评论。这不会重现 join()
的行为,如果您在 Thread.start()
和同步块之间添加睡眠时间比其他线程睡眠时间更长,代码将挂起(而 join()
不会)...
您问题的答案隐藏在 Thread.join()
的 Javadoc 中
As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.
我认为 Javadoc 中提到的对 this.notifyAll()
的调用是本机的,因为我在 Thread
.
的源代码中的任何地方都找不到它
我在下面找到了复制 Java 中的 join() 行为的代码。有两种可能的执行路径:
- 当Main线程继续执行并进入synchronized块时。 然后它必须等待线程 t 完成。
- 当Thread t先启动并调用运行方法时,Main线程等待获取锁。
在这两种情况下,都没有 notify(),但程序仍会以适当的输出完成。你能告诉我为什么主线程没有永远等待,因为没有 notify() 吗?
public class SequentialTreadWithoutJoin {
public static void main(String[] args) {
MyThread t = new MyThread("myThread");
t.start();
synchronized(t){
try {
System.out.println("Before wait");
t.wait();
System.out.println("After wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i = 0; i < 10; i++)
System.out.println("Thread " + Thread.currentThread().getName() + " will continue after join and print : " + i );
}
}
class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
public synchronized void run(){
System.out.println("Thread " + this.getName() + " will run for 1 minute");
try {
this.sleep(60000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
同步块工作
同步是围绕称为内部锁或监视器锁的内部实体构建的。 (API 规范通常将此实体简称为 "monitor.")内在锁在同步的两个方面都发挥作用:强制对对象状态的独占访问和建立对同步至关重要的先行关系能见度。
每个对象都有一个与之关联的内部锁。按照惯例,需要对对象字段进行独占和一致访问的线程必须在访问它们之前获取对象的内部锁,然后在完成访问后释放内部锁。据说线程在获取锁和释放锁之间拥有内部锁。只要一个线程拥有一个内在锁,其他线程就不能获取同一个锁。另一个线程在尝试获取锁时将阻塞。
当线程释放内在锁时,在该操作与同一锁的任何后续获取之间建立了先行关系。
同步方法中的锁
当线程调用同步方法时,它会自动获取该方法对象的内部锁,并在方法 return 时释放它。即使 return 是由未捕获的异常引起的,也会发生锁定释放。
如果没记错的话,你的主线程调用等待线程t,但是wait()只能从线程本身调用。没有人可以调用您的 wait()。所以 t.wait() 是没有用的,因为它不是 t 本身调用的,而是主线程调用的。
t.wait() 应该是 t.join()。在这种情况下,主线程将等待线程 t 完成。此外,整个同步块都可以去,因为它只有一个线程去那里。 t 永远不会到达该代码,因为 t 只运行 MyThread.run().
的代码所以在 t.start() 之后一个简单的 t.join() 会延迟主线程直到 t 完成。
更新:正如 Augusto 强调的那样,该程序依赖于 JDK 的隐式行为才能正常工作。赞成他的回答。
先来个评论。这不会重现 join()
的行为,如果您在 Thread.start()
和同步块之间添加睡眠时间比其他线程睡眠时间更长,代码将挂起(而 join()
不会)...
您问题的答案隐藏在 Thread.join()
As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.
我认为 Javadoc 中提到的对 this.notifyAll()
的调用是本机的,因为我在 Thread
.