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

时间:2011-12-14 05:11:00

标签: java multithreading

所以我有以下代码:

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();}
}
}

输入两个参数:数字n和要创建的线程数。每个线程将n减1,然后通过控制。当n为0时,所有线程都应该停止。到目前为止似乎工作正常,但唯一的问题是在大多数情况下除了一个终止之外的所有线程。而且还有一个问题。知道为什么吗?

是的,这是家庭作业的一部分,这就是我到目前为止所做的事情(我没有提供代码)。我还明确限制使用同步块,并且任务只使用wait().notify()方法。

编辑:稍微修改了同步块:

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;
  }

现在线程严格按照创建顺序执行。从任务措辞中可以清楚地看出,但可能是正确的。

2 个答案:

答案 0 :(得分:0)

你有竞争条件。想想单个工作线程会发生什么。 Global.n设置为1,然后线程启动。它立即进入等待状态。但是假设已经在主线程上调用notify()。由于工作线程尚未进入等待状态,因此不会通知它。然后,当它最终调用wait()时,没有其他线程可以调用notify(),它永远处于等待状态。你需要修正你的逻辑以避免这种竞争条件。

另外,您真的希望单个工作线程不止一次递减Global.n吗?您的while (true) ...循环很容易发生这种情况。

修改 单个线程也有另一个逻辑问题。假设它进入等待状态,然后调用notify()中的main。它唤醒工作线程,将Global.n递减为0,调用notify(),然后返回等待。问题是notify()没有唤醒任何其他线程,因为没有其他线程可以唤醒。所以一个工作线程将永远等待。我没有完全分析它,但是这样的事情也可能发生在多个工作线程中。

答案 1 :(得分:0)

你应该永远不会有一个裸的wait()调用,因为java中的信号量没有被缓存。 wait()应该总是嵌套在某种

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