我想使用多线程(低级线程),但我遇到了一个问题。问题是因为至少wait方法将被一个线程调用而notifyAll将被另一个线程调用,问题是任何时候我运行程序,在我看来notifyAll在等待之前被调用,所以我"将永远等待"。
我的代码如下:
public class Reader extends Thread {
Calculator c;
public Reader(Calculator cal) {
c=cal;
}
public void run (){
synchronized(c) {
try {
System.out.println("Waiting for calculation");
c.wait();
} catch (InterruptedException ex) {}
System.out.println("Total is:" +c.total);
}
}
public static void main (String[] a) {
Calculator calculator=new Calculator();
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
}
}
class Calculator implements Runnable {
int total;
public void run() {
synchronized(this) {
for(int i=0;i<100;i++) {
total=total+i;
}
notifyAll();
}
}
}
我在这里输出的是连续5次等待计算,所以我从未达到声明&#34;总数是总数。
我试图弄清楚如何解决问题,但仍未找到解决方案。如果有人有任何线索该做什么我将非常感激。
提前致谢
答案 0 :(得分:1)
您实际上并没有执行计算器可运行的代码,您拥有的代码不会计算总数或通知任何内容。使用计算器启动一个新线程:
new Thread(calculator).start();
在您初始化计算器局部变量的行之后。这将使计算器在主线程启动读者时开始工作。
可能计算器可能在读者开始等待之前完成,读者最终会等待永远不会发出的通知。创建一个条件变量,在这种情况下,向Calculator添加一个布尔标志,初始化为false,一旦计算完成就设置为true(通过notifyAll,在离开synchronized块之前)。让读者等待循环:
synchronized(c) {
try {
System.out.println("Waiting for calculation");
while (!c.finished) {
c.wait();
}
} catch (InterruptedException ex) {}
System.out.println("Total is:" +c.total);
}
这样,如果计算器在读者开始之前完成,读者将从条件变量中判断出计算器已完成且不会等待。
总是在循环中调用wait方法是个好习惯,因为
a)当线程接收到没有锁的通知时,在通知线程和重新获取锁之间的时间内,由于其他线程的操作,系统状态可能会发生变化(不是本例中的情况)和
b)你不能依赖终止等待意味着线程收到通知。通过以上更改,程序正常完成此输出:
Waiting for calculation
Total is:4950
Waiting for calculation
Total is:4950
Waiting for calculation
Total is:4950
Waiting for calculation
Total is:4950
Waiting for calculation
Total is:4950
以下是完整的修订代码:
public class Reader extends Thread {
Calculator c;
public Reader(Calculator cal) {
c=cal;
}
public void run (){
synchronized(c) {
try {
System.out.println("Waiting for calculation");
while (!c.finished) {
c.wait();
}
} catch (InterruptedException ex) {}
System.out.println("Total is:" +c.total);
}
}
public static void main (String[] a) {
Calculator calculator=new Calculator();
new Thread(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
}
}
class Calculator implements Runnable {
int total;
boolean finished;
public void run() {
synchronized(this) {
finished = false;
for(int i=0;i<100;i++) {
total=total+i;
}
notifyAll();
finished = true;
}
}
}
答案 1 :(得分:0)
我建议澄清一下您对最终结果的期望。显然500?不确定:P
无论如何,我建议使用Java Executors。它们是以有组织的方式处理执行线程的默认Java类。试试这个:
public class Example {
public static class Calculator implements Runnable {
private int result = 0;
public void run() {
for (int i = 0; i < 100; i++) {
result++;
}
System.out.println("Done. Result = " + result);
}
public int getResult() {
return result;
}
}
public static void main(final String[] args) {
final Calculator c = new Calculator();
final ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(c);
executorService.submit(c);
executorService.submit(c);
executorService.submit(c);
executorService.submit(c);
}
}
这给我以下内容:
Done. Result = 100
Done. Result = 200
Done. Result = 300
Done. Result = 400
Done. Result = 500
这段代码的作用是创建一个单线程执行器,它可以运行任务(Runnable
个对象)并为此使用单个线程。因为它使用单个线程,所以每个任务必须等待它之前的任务才能启动。
如果你创建了一个多线程执行器,它将尝试在可用的线程中运行任务,并且所有线程都遵循与单线程一样的原则:对于每个线程,任务必须等待一个线程在它开始之前。但正如名称所说,使用多线程执行程序,有多个线程,这意味着任务将同时运行,并且现在将显示相同的行为。
希望这有帮助!
答案 2 :(得分:0)
尽管你写过关于低级线程的文章,但很清楚你的问题可以通过ForkJoinPool来解决。关键是你可以使用wait
- notify
来电轻松搞错;但是&#34;发生在&#34;可以使用wait
方法而不是调用join
来设置关系。
完整代码:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Reader extends Thread {
final Future<Integer> future;
public Reader(Future<Integer> future) {
this.future = future;
}
@Override
public void run() {
try {
int result = future.get();
System.out.println("Total is:" + result);
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] a) {
Calculator calculator = new Calculator();
ForkJoinPool pool = ForkJoinPool.commonPool();
ForkJoinTask calcTask = pool.submit(calculator);
ForkJoinTask[] tasks = {
calcTask,
pool.submit(new Reader(calcTask)),
pool.submit(new Reader(calcTask)),
pool.submit(new Reader(calcTask)),
pool.submit(new Reader(calcTask)),
pool.submit(new Reader(calcTask))
};
//do something else
for (ForkJoinTask task : tasks) {
task.join();
}
}
}
class Calculator implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int total = 0;
for (int i = 0; i < 100; i++) {
total = total + i;
}
return total;
}
}