2011-08-01 148 views
4

我有产生这样的结果,例如以下2类代码:Java线程同步问题

Wainting for calculation to complete... 
Calculator thread says HELLO! 
T1 says that total is 10 
Wainting for calculation to complete... 
Wainting for calculation to complete... 

现在线程在等待,但没有人会通知他们。 如何在“计算器线程”唤醒em之前强制T1至T3的线程运行?

public class Calculator implements Runnable{ 

    private int total; 

    public int getTotal() { 
    return total; 
    } 

    @Override 
    public void run() { 
    synchronized (this) { 

     for (int i = 0; i < 5; i++) { 
      total += i; 
     } 
     System.out.println(Thread.currentThread().getName() + " says HELLO!"); 
     notifyAll(); 
    } 
    } 
} 


import static java.lang.System.out; 

public class Reader implements Runnable{ 

    private Calculator c; 


    public Reader(Calculator calc) { 
    c = calc; 
    } 

    public Calculator getCalculator() { 
    return c; 
    } 

    public static void main(String[] args) { 

    Calculator calc = new Calculator(); 
    Reader read = new Reader(calc); 

    Thread thread1 = new Thread(read); 
    Thread thread2 = new Thread(read); 
    Thread thread3 = new Thread(read); 

    thread1.setName("T1"); 
    thread2.setName("T2"); 
    thread3.setName("T3"); 

    thread1.start(); 
    thread2.start(); 
    thread3.start(); 

    Thread calcThread = new Thread(read.getCalculator()); 
    calcThread.setName("Calculator thread"); 
    calcThread.start(); 
    } 
} 


    @Override 
    public void run() { 
     synchronized (c) { 
      try { 
       out.println("Wainting for calculation to complete..."); 
       c.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      out.println(Thread.currentThread().getName() + " says that " + "total is " + c.getTotal()); 
     } 

    } 

} 
+0

我可以在thread3.start()之后添加Thread.sleep(),但我认为这不是一个合适的解决方案。 – nyxz

+0

您不应该使用wait/notify,而应该使用来自java.util.concurrent的调试实用程序,并相应地完全重新设计您的应用程序。目前还不清楚你的真实应用是什么,所以我不能告诉你你应该使用什么。 – toto2

+0

@toto:没有理由不使用wait/notify。他们是简单和灵活的原始人。 java.util.concurrent类只是相同的包装器。我同意更高层次的构造,例如读写锁,这些类提供的障碍和锁闩......但是当一个简单的锤子就足够时,你永远不应该使用铁砧。 –

回答

0

的Thread.join(怎么可能看起来像在这种特殊情况的选项。由于您可以控制main()函数,并且您确切知道每个线程何时启动。

来处理这种情况更普遍的方式是使用条件变量和调用c.wait()一个循环中检查条件变量。

基本上添加isFinished字段中Calculator类:

 
public class Calculator implements Runnable { 
... 
    public volatile boolean isFinished = false 
.. 
.. 

然后更换c.wait()有:

 
... 
while (!c.isFinished) { 
    c.wait(); 
} 
... 

最后,在你的计算器类的run()方法计算总后,设置isFinished场

 
.... 
for(int i = 0; .... 
    total = += i; 
} 
c.isFinished = true 
.... 
+0

我也会尝试,谢谢 – nyxz

+0

这没有帮助。 – nyxz

+0

对不起,我的坏!它有助于:)这是一个很好的简单解决方案。 – nyxz

3

这是我如何写代码。我没有试图用wait/notify来重新发明轮子,而是使用并发库来做需要的事情,一个未来。

import java.util.concurrent.*; 

public class Main { 
    static final long start = System.nanoTime(); 

    static void log(String text) { 
     double seconds = (System.nanoTime() - start)/1e9; 
     System.out.printf("%s %.6f - %s%n", Thread.currentThread().getName(), seconds, text); 
    } 

    static class Calculator implements Callable<Integer> { 
     @Override 
     public Integer call() throws Exception { 
      int total = 0; 
      log("calculating total"); 
      for (int i = 0; i < 50000; i++) 
       total += i; 
      log("total is " + total); 
      return total; 
     } 
    } 

    static class Reader implements Callable<Void> { 
     private final Future<Integer> totalFuture; 

     public Reader(Future<Integer> totalFuture) { 
      this.totalFuture = totalFuture; 
     } 

     @Override 
     public Void call() throws ExecutionException, InterruptedException { 
      log("Waiting for total."); 
      int total = totalFuture.get(); 
      log("... got total= " + total); 
      return null; 
     } 
    } 

    public static void main(String... args) { 
     ExecutorService es = Executors.newCachedThreadPool(); 
     Future<Integer> totalFuture = es.submit(new Calculator()); 
     es.submit(new Reader(totalFuture)); 
     es.submit(new Reader(totalFuture)); 
     es.submit(new Reader(totalFuture)); 
     es.shutdown(); 
    } 
} 

打印

pool-1-thread-1 0.008154 - calculating total 
pool-1-thread-4 0.011356 - Waiting for total. 
pool-1-thread-3 0.011292 - Waiting for total. 
pool-1-thread-2 0.011128 - Waiting for total. 
pool-1-thread-1 0.025097 - total is 1249975000 
pool-1-thread-4 0.025351 - ... got total= 1249975000 
pool-1-thread-3 0.025372 - ... got total= 1249975000 
pool-1-thread-2 0.025380 - ... got total= 1249975000 

thread3.start(); 

之后加上等待线程完成。

thread1.join(); 
thread2.join(); 
thread3.join(); 
+0

超级!谢谢,彼得! – nyxz

+0

我编辑了代码。我错误地删除了一些卷。 如果我添加这段代码,线程真的在等待完成,程序永远不会到达calcThread.start();女巫调用notifyAll()方法...所以程序永远不会结束。 还有其他建议吗? – nyxz

+0

问题是,我将删除所有不需要的代码,直到您只有一个循环来计算总数和一个打印语句。其他一切都没有做任何事情。 –

0

U可以使用Thread.join()方法。我不知道)的良好的编程习惯,但是,将工作abouts ..

+0

查看评论我留在彼得·劳里使用加入() – nyxz