多线程状态依赖问题

时间:2011-06-27 21:09:01

标签: java multithreading concurrency

我收到了以下代码段:

public class ThreadTest{

  private static class Thread01 extends Thread{
    private Thread02 _th2; 
    public int foo = 0;

    public void setThrd02(Thread02 thrd2){
       _th2 = thrd2;
    }

    public void run(){
      try{
        for(int i=0;i<10;i++) foo += i;

        synchronized(this){this.notify();};

        synchronized(_th2){_th2.wait();};

        System.out.print(" Foo: " + _th2.foo);
      }catch(InterruptedException ie){ ie.printStackTrace();}    
    }
  }

  private static class Thread02 extends Thread{

    private final Thread01 _th1;
    public int foo = 0;

    public Thread02(Thread01 th1){
      _th1 = th1;
    }

    public void Run(){
       try{
         synchronized(_th1){_th1.wait();}
         foo = _th1.foo;

         for(int i=0;i<10;i++) foo += i;
         synchronized(this){this.notify();};
           }
       catch(InterruptedException ie){ie.printStackTrace();}

    }

  }

  public static void main(){
    Thread01 th1 = new Thread01();
    Thread02 th2 = new Thread02(th1);

    th1.setThrd02(th2);

    th1.start(); th2.start();
    th1.join(); th2.join();
  } 
}

我认为代码的假设和相应目的就像 th2先运行,通过调用_th1.wait()更改为等待状态; 然后,th1计算foo并唤醒th2,th1进入等待状态; Th2从thread1读取foo并更新为110,然后唤醒th1和th2退出。 然后th1退出。

线程可能非常危险,因为线程1很可能先运行而线程2将永远等待。

我不确定代码的任何其他潜在问题。

解决问题的一种可能方法是,例如在thread1

public class ThreadTest {

private static boolean updated = false; private static boolean finished = false;

private static Thread01扩展了Thread {

public void Run(){     //做计算     而(成品){       等待();     }     //输出结果   } }

private static Thread02扩展Thread { public void run(){

而(假){      等待();   }

foo = th1.foo;   //做计算   //通知线程1的类似机制 } }

3 个答案:

答案 0 :(得分:4)

无法保证您的帖子中有订单。 Thread01过去就足够了 {02}在Thread02执行synchronized(this){this.notify();};以使两个线程无限期地等待之前synchronized(_th1){_th1.wait();}

注意:您在_th1和_th2上调用waitnotify这一事实无关紧要。此处的线程将被视为任何其他对象。

答案 1 :(得分:2)

@Alex已经指出了wait和notify未按代码期望的顺序调用的问题(+1)。但是,由于这是一个面试问题,因此该代码还有其他一些问题:

  1. 可怕的命名约定和代码格式,
  2. 公共字段访问者,
  3. 在Thread对象上进行同步(奇异),
  4. 捕获InterruptedException,然后退出Thread,
  5. 无异常处理,
  6. (个人偏好)不使用Java并发库。
  7. 我确定提出的问题是将你打结并解决为什么并发性被打破但是,恕我直言,那段代码是如此可怕,我甚至不会开始调试它 - 我只是扔掉它

答案 2 :(得分:0)

以下可以是更好的修复

public class ThreadTest{
  private static volatile boolean updated = false; 
  private static volatile boolean finished = false;


   private static class Thread01 extends Thread{
    private Thread02 _th2; 
    public int foo = 0;

    public void setThread2(Thread02 th2){
        _th2 = th2;
    }

    public void Run(){          

        for(int i=0;i<10;i++) foo += i;
        System.out.print(" thread1 calcualtion " + foo + "\n");

        try{
        updated = true; 
        synchronized(this) {this.notify();};

        synchronized(_th2){
             while(!finished) 
                 _th2.wait();
             System.out.print("Foo: " + _th2.foo );    
          } 
    } 
    catch(InterruptedException ie){
        ie.printStackTrace();
    }
}
 }

  private static class Thread02 extends Thread{ 
    private final Thread01 _th1;
    public int foo = 0;

    public Thread02(Thread01 th1){
        _th1 = th1;
    }
    public void run(){
    try{
        synchronized(_th1){
            while(!updated) 
                _th1.wait();
        foo = _th1.foo; 
        } 
    for(int i=0;i<10;i++) foo +=i; 
    finished = true; 
    synchronized(this){ this.notify();}
    }catch(InterruptedException ie){
        ie.printStackTrace();
    }
}
 }

public static void main(String[] args) {
    // TODO Auto-generated method stub
    Thread01 th1 = new Thread01();
    Thread02 th2 = new Thread02(th1);

    th1.setThread2(th2);

    try{
    th1.start();
    th2.start();
    th1.join();
    th2.join();
    }catch(InterruptedException ie){
        ie.printStackTrace();
    }
}
相关问题