为什么等待线程不会永远等待

时间:2015-03-07 18:37:03

标签: java multithreading concurrency

我在下面找到了用于在Java中复制join()行为的代码。有两种可能的执行路径:

  1. 当主线程继续执行并进入同步块时。 然后它必须等待线程t完成。
  2. 当线程t首先启动并调用run方法时,Main线程等待获取锁定。
  3. 在这两种情况下都没有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();
            }
        }
    }
    

3 个答案:

答案 0 :(得分:4)

首先评论。这不会重现join()的行为,如果您在Thread.start()和同步块之间添加休眠时间比其他线程休眠的时间长,则代码会挂起(而{{1}不愿意......

你的问题的答案隐藏在Thread.join()

的Javadocs中
  

当一个线程终止时,将调用this.notifyAll方法。建议应用程序不要在Thread实例上使用wait,notify或notifyAll。

我认为Javadoc中提到的对join()的调用是原生的,因为我在this.notifyAll()的源代码中找不到它。

答案 1 :(得分:-1)

同步块工作

同步是围绕称为内部锁或监视器锁的内部实体构建的。 (API规范通常将此实体简称为&#34;监视器。&#34;)内部锁在同步的两个方面都发挥作用:强制独占访问对象的状态并建立发生在之前对可见性至关重要的关系。

每个对象都有一个与之关联的内在锁。按照惯例,需要对对象字段进行独占和一致访问的线程必须在访问对象之前获取对象的内部锁,然后在完成它们时释放内部锁。据说一个线程在获得锁定和释放锁定之间拥有内在锁定。只要一个线程拥有一个内部锁,没有其他线程可以获得相同的锁。另一个线程在尝试获取锁时会阻塞。

当线程释放内部锁时,在该操作与同一锁的任何后续获取之间建立先发生关系。

锁定同步方法

当线程调用synchronized方法时,它会自动获取该方法对象的内部锁,并在方法返回时释放它。即使返回是由未捕获的异常引起的,也会发生锁定释放。

答案 2 :(得分:-1)

如果没有弄错,你的主线程调用等待线程t,但wait()只能从线程本身调用。没有人可以打电话给你的等待()。所以t.wait()是无用的,因为它不是由t本身调用而是由主线程调用。

t.wait()应该是t.join()。在这种情况下,主线程将等待线程t完成。此外,整个同步块可以去,因为它只有一个线程。 t永远不会到达该代码,因为t只运行MyThread.run()的代码。

所以在t.start()之后,一个简单的t.join()会延迟主线程直到t结束。

更新:正如Augusto强调的那样,该程序依赖于JDK的隐式行为才能正常工作。赞成他的回答。