Java线程同步问题

时间:2011-08-01 14:37:20

标签: java

我有以下2个类代码,例如:

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...

现在线程正在等待,但没有人会通知他们。 如何在“计算器线程”唤醒之前强制线程从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());
      }

  }

}

3 个答案:

答案 0 :(得分: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();

答案 1 :(得分:0)

你可能会使用Thread.join()方法..我不确定如何进行良好的编程实践,但这会有效..

答案 2 :(得分: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();
}
...

最后在计算total之后计算器类的`run()方法中,设置isFinished字段

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