简体   繁体   English

Java同步块,并非所有线程都被终止

[英]Java synchronized block, not all the threads get terminated

So I have the following code: 所以我有以下代码:

import java.lang.Thread;
import java.lang.Integer;

class MyThread extends Thread {
private int id;

MyThread(int i){
    id = i;
    }

public void run() {
    while(true){
        try{                    
            synchronized(Global.lock){
                Global.lock.wait();
                if(Global.n == 0) {System.out.println(id); Global.lock.notify(); break;}
                --Global.n;
                System.out.println("I am thread " + id + "\tn is now " + Global.n);
                Global.lock.notify();
                }
            }
        catch(Exception e){break;}
        }
    }
}

class Global{
public static int n;
public static Object lock = new Object();
}

public class Sync2{
public static final void main(String[] sArgs){
    int threadNum = Integer.parseInt(sArgs[0]);
    Global.n = Integer.parseInt(sArgs[1]);

    MyThread[] threads = new MyThread[threadNum];

    for(int i = 0; i < threadNum; ++i){
        threads[i] = new MyThread(i);
        threads[i].start();     
        }
    synchronized(Global.lock){Global.lock.notify();}
}
}

two parameters are entered: a number n and the number of threads to be created. 输入两个参数:数字n和要创建的线程数。 Every thread decreases n by one and then passes control. 每个线程将n减1,然后通过控制。 All threads should stop when n is 0. It seems to work fine so far, but the only problem is that in most of the cases all threads except one terminate. 当n为0时,所有线程都应停止。到目前为止,看来一切正常,但是唯一的问题是,在大多数情况下,除一个线程外,所有线程都终止。 And one is hanging on. 一个正在挂。 Any idea why? 知道为什么吗?

And yes, this is part of a homework, and that is what I've done so far (I was no provided with the code). 是的,这是家庭作业的一部分,这是我到目前为止所做的(代码未提供)。 I'am also explicitly restricted to use a synchronized block and only wait() and .notify() methods by the task. 我也明确限制使用该任务的同步块,并且仅使用wait().notify()方法。

EDIT: modified the synchronized block a bit: 编辑:修改了同步块有点:

synchronized(Global.lock){
  Global.lock.notify();
  if (Global.n == 0) {break;}
  if (Global.next != id) {Global.lock.wait();  continue;}
  --Global.n;
  System.out.println("I am thread " + id + "\tn is now " + Global.n);
  Global.next = ++Global.next % Global.threadNum;
  }

now threads act strictly in the order they are created. 现在,线程严格按照创建顺序执行操作。 Its pretty unclear from the task wording, but might be the right thing. 从任务措辞上还不清楚,但可能是对的。

You have a race condition. 您有比赛条件。 Think about what happens with a single worker thread. 考虑单个工作线程会发生什么。 Global.n is set to 1 and then the thread starts. Global.n设置为1,然后线程启动。 It immediately goes into a wait state. 它立即进入等待状态。 Suppose, though, that notify() had already been called on the main thread. 但是,假设已经在主线程上调用了notify() Since the worker thread hasn't yet entered a wait state, it isn't notified. 由于工作线程尚未进入等待状态,因此不会收到通知。 Then, when it finally does call wait() , there are no other threads around to call notify() , it stays in the wait state forever. 然后,当它最终确实调用wait() ,周围没有其他线程可以调用notify() ,它永远保持在等待状态。 You need to fix up your logic to avoid this race condition. 您需要修正逻辑以避免这种竞争状况。

Also, do you really want a single worker thread to decrement Global.n more than once? 另外,您是否真的希望单个工作线程多次减少Global.n That can easily happen with your while (true) ... loop. 使用while (true) ...循环很容易发生这种情况。

EDIT You also have another logic problem with a single thread. 编辑您也有一个线程的另一个逻辑问题。 Suppose it enters the wait state and then the notify() in main is called. 假设它进入等待状态,然后调用mainnotify() It wakes the worker thread which decrements Global.n to 0, calls notify() , and then goes back to waiting. 它唤醒将Global.n递减为0的工作线程,调用notify() ,然后返回等待状态。 The problem is that notify() didn't wake any other thread because there were no other threads to wake. 问题在于notify()没有唤醒任何其他线程,因为没有其他线程可以唤醒。 So the one worker thread will wait forever. 因此,一个工作线程将永远等待。 I haven't analyzed it fully, but something like this might also happen with more than one worker thread. 我还没有对它进行完整的分析,但是类似的事情也可能发生在多个工作线程上。

You should never have a naked wait() call, as semaphores in java are not cached. 永远不要裸露的wait()调用,因为不缓存Java中的信号量。 wait() should always be nested in some sort of wait()应该总是嵌套在某种形式的

while (condition that you are waiting on)
    obj.wait();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM