线程处于无限等待状态

Thread is going in infinite wait state

提问人:Avenger 提问时间:6/16/2023 更新时间:6/16/2023 访问量:58

问:

给定一个整数 N,任务是编写一个 Java 程序,使用两个线程按递增顺序打印前 N 个自然数。但是,输出仅显示数字 1,因为线程正在进入无限循环,这是用户无法调试的。

public class OddEven {
    static int totalNos;
    static int counter = 1;
    static Runnable odd = new Runnable() {
        @Override
        public void run() {
            synchronized (this) {
                while(counter < totalNos) { 
                    while (counter%2==0) {
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(counter + " ");
                    counter++;
                    notify();
                }
            }
        }
    };
    
    static Runnable even = new Runnable() {
        @Override
        public void run() {
            synchronized (this) {
                while(counter < totalNos) {
                    while (counter%2==1) {
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.print(counter + " ");
                    counter++;
                    notify();
                }
            }
        }
    };
    
    public static void main(String[] args) {
        System.out.println("Enter the total no's");
        Scanner scObj = new Scanner(System.in);
        totalNos = scObj.nextInt();
        scObj.close();
        Thread oddT1 = new Thread(odd);
        Thread evenT1 = new Thread(even);
        oddT1.start();
        evenT1.start();  
      
    }
}
Java 多线程 JVM 等待 通知

评论

1赞 markspace 6/16/2023
顺便说一句,这种交错——在短时间内运行一个线程,然后等待另一个线程——几乎总是不是你想在现实世界中做的事情。线程通常应该被赋予大量的工作来适当地摊销其开销。
0赞 markspace 6/16/2023
我的第一个观察是,几乎可以肯定的是,每个线程都会看到更新。countervolatile
0赞 Samuel Marchant 6/16/2023
而 (counter%2==1) 它出现,而其他代码是条件的“副本”。线程显示为复印件,因此在等待时满足相同的要求,因此两者都处于相同的状态。最好定义这两个条件,并遍历您的工作顺序以检查它是否一个接一个。
1赞 Holger 6/16/2023
@markspace 否,如果没有使用不同对象进行同步的基本问题,则不需要。volatile
1赞 Holger 6/16/2023
@markspace在修复程序时,要在两个线程中使用相同的对象,同步会负责内存可见性。通过正确的同步,两个线程不可能在这里同时运行,因为一个线程只能从另一个线程离开块或进入时返回,换句话说,以某种方式释放锁,因为返回意味着重新获取锁。在释放锁和随后获取同一锁之间存在“发生之前”关系。synchronizedwaitsynchronizedwaitwait

答:

1赞 Solomon Slow 6/16/2023 #1

两个对象之间没有同步。你的两个对象中的每一个,都在它自己身上同步,在它自己身上等待,并通知它自己。或者,更准确地说,如果它到达那个点,它会通知自己,但它没有到达那里,因为另一个线程永远不会通知它。evenodd

您需要让两个线程使用相同的对象进行同步。例如;

public class OddEven {
    static final Object lock = new Object();
    static int totalNos;
    static int counter = 1;
    static Runnable odd = new Runnable() {
        @Override
        public void run() {
            synchronized (lock) {
                ...
                lock.wait();
                ...
                lock.notify();
            }
        }
    }
    .
    .
    .
}

评论

1赞 user16320675 6/16/2023
我建议添加 - 通常我们不希望外部代码能够通知它(可能对所有字段都有效......privatelock
1赞 Holger 6/16/2023
你如何使用“自我”来避免“”很奇怪。此外,你的措辞将初学者推向了错误的方向,认为 和 是对象,而不是包含对对象的引用的变量。thisevenodd
0赞 Solomon Slow 6/16/2023
@Holger,这很有趣,因为我通常是第一个提请注意变量与对象和对象引用之间的区别的人,而不理解它是某人问题的根源;但这里的情况并非如此。我想提请注意这样一个事实,即每个线程都有自己独特的委托,并且很自然地叫出它们的名字。我敢肯定,我们所有人都会使用变量的名称来识别它们所指的对象,而不可能误解哪个对象的含义。
0赞 Solomon Slow 6/16/2023
@Holger,Re,“'self'来避免'this'”,我并没有有意识地试图避免任何事情,尽管我一直觉得与其他语言相比,Java 有些尴尬。如果我不被允许说“自我”,我将不得不花更多的文字来表达“它自己的自我”所包含的想法。此外,如果我只是简单地说,“每个对象都同步”,我就不会告诉 OP 任何他们不知道的事情。这在他们自己的代码中是明确的。thisselfthis
1赞 Holger 6/16/2023
在 和 调用的情况下,它们在 上被调用并不是那么明显。但是,是的,重要的一点不是这两个线程在“this”上同步,而是“this”指的是不同的对象。这是已传递给两个构造函数的两个实例。但也许,你的措辞对于初学者来说更容易掌握;从 OP 那里获得反馈是否有帮助将非常有用......wait()notify()thisRunnableThread