Java 为什么线程不进入无限时间等待状态?

Java 为什么线程不进入无限时间等待状态?,java,multithreading,Java,Multithreading,下面是我在本地机器上运行时成功完成执行的代码段 我无法理解为什么这个线程没有进入无限等待状态 public class Job extends Thread { private int counter; @Override public void run() { synchronized (this) { for (int i = 0; i < 100000; i++) { counter+

下面是我在本地机器上运行时成功完成执行的代码段

我无法理解为什么这个线程没有进入无限等待状态

public class Job extends Thread {

    private int counter;

    @Override
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 100000; i++) {
                counter++;
            }

            this.notifyAll();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Job job = new Job();
        job.start();
        synchronized (job) {
            job.wait();
        }

        System.out.println(job.counter);
    }
}
公共类作业扩展线程{
专用int计数器;
@凌驾
公开募捐{
已同步(此){
对于(int i=0;i<100000;i++){
计数器++;
}
this.notifyAll();
}
}
公共静态void main(字符串[]args)引发InterruptedException{
作业=新作业();
job.start();
已同步(作业){
job.wait();
}
系统输出打印LN(作业计数器);
}
}

有没有保证上述代码在任何情况下都能完成执行?有人能澄清一下吗?

有几种可能性

  • 主线程首先进入
    synchronized
    wait()
    s。在这种情况下,程序将终止,因为
    作业
    线程
    将调用
    同步
    对象上的
    通知()
  • 作业
    线程
    首先进入
    同步
    块,并在主
    线程
    调用
    等待()
    之前调用
    通知()
    ,即主
    线程
    无法,因为它在
    同步
    块等待。这将阻止应用程序,因为主
    线程将无法从
    wait()
    调用返回

  • 看起来你手头确实有一个任务-这取决于哪个
    同步(作业)
    首先发生-是在主线程中还是在作业中

    我不明白为什么这个线程没有进入无限等待 地位

    它可以,如果在
    job.wait()
    之前调用
    this.notifyAll()
    ,就会发生这种情况

    添加一个标记以测试是否完成,如下所示:

    public class Job extends Thread {
    
        private int counter;
        private boolean finished = false;
    
        @Override
        public void run() {
            synchronized (this) {
                for (int i = 0; i < 100000; i++) {
                    counter++;
                }
    
                finished = true;
                this.notifyAll();
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Job job = new Job();
            job.start();
            synchronized (job) {
                while (!job.finished)
                    job.wait();
            }
    
            System.out.println(job.counter);
        }
    }
    
    公共类作业扩展线程{
    专用int计数器;
    private boolean finished=false;
    @凌驾
    公开募捐{
    已同步(此){
    对于(int i=0;i<100000;i++){
    计数器++;
    }
    完成=正确;
    this.notifyAll();
    }
    }
    公共静态void main(字符串[]args)引发InterruptedException{
    作业=新作业();
    job.start();
    已同步(作业){
    而(!作业。已完成)
    job.wait();
    }
    系统输出打印LN(作业计数器);
    }
    }
    

    这样,您就可以保证程序不会陷入竞争状态,并将永远等待。还要注意的是,现在您可以保护自己不受影响。

    除了虚假的唤醒问题(大多数情况下不会影响这种简单的使用)之外,您应该希望代码始终能够完成


    您似乎缺少的一件事是
    job.wait()
    释放锁,允许执行另一个
    已同步的
    块,并调用
    notifyAll()
    。此时,
    wait
    唤醒,main方法退出。

    作业的run方法上的睡眠不会导致死锁吗?@zmbq我不这么认为,因为当它切换上下文时,另一个线程仍在等待,因此它将切换回。只有一个线程可以同时进入
    synchronized
    块,对吗?如果作业执行,则一切正常(作业运行循环、通知并退出)。如果它是主线程,作业将无法运行。我错过什么了吗?@zmbq不,你知道了。我想这就是我在问题中写的。如果主线程休眠,作业线程将进入并完成其同步。它将在主线程
    wait()
    sKeep之前发出通知。记住,wait方法将在阻塞之前释放同步对象的所有权。我想这就是你丢失的链接。等等,()可能会在没有通知的情况下冒然醒来。这就是为什么您应该始终使用notify更改同步块中的状态,并始终使用wait()更改循环中的状态更改。在您的代码中,没有任何保证。