[英]Proper synchronization of Java threads using wait/notifyAll?
这是我的应用程序的简化版本,显示了我在做什么。
/*
in my app's main():
Runner run = new Runner();
run.dowork();
*/
class Runner
{
private int totalWorkers = 2;
private int workersDone = 0;
public synchronized void workerDone()
{
workersDone++;
notifyAll();
}
public synchronized void dowork()
{
workersDone = 0;
//<code for opening a file here, other setup here, etc>
Worker a = new Worker(this);
Worker b = new Worker(this);
while ((line = reader.readLine()) != null)
{
//<a large amount of processing on 'line'>
a.setData(line);
b.setData(line);
while (workersDone < totalWorkers)
{
wait();
}
}
}
}
class Worker implements Runnable
{
private Runner runner;
private String data;
public Worker(Runner r)
{
this.runner = r;
Thread t = new Thread(this);
t.start();
}
public synchronized void setData(String s)
{
this.data = s;
notifyAll();
}
public void run
{
while (true)
{
synchronized(this)
{
wait();
//<do work with this.data here>
this.runner.workerDone();
}
}
}
}
这里的基本概念是,我有一堆工人,他们都对传入的数据行进行全部独立的处理,并在需要的地方写出数据-他们不需要将任何数据报告回主线程或彼此共享数据。
我遇到的问题是此代码死锁。 我正在读取超过100万行的文件,很幸运在我的应用停止响应之前将100行插入其中。
实际上,这些工人的工作量是不同的,因此我想等到他们全部完成后再转到下一行。
我不能让工作人员以不同的速度处理数据并在内部将数据排队,因为我正在处理的文件太大,无法容纳在内存中。
我不能给每个工作人员自己的FileReader来独立获取“行”,因为我在工作人员看到该行之前对其进行了大量处理,并且不想在每个工作人员中都重新进行处理。
我知道我在Java中缺少一些相当简单的同步方面,但是我仍然停留在这一点上。 如果有人可以在这里解释我在做什么错,我将不胜感激。 我相信我误解了同步的某些方面,但是出于尝试修复同步的想法。
直接使用synchronized
, wait()
和notify()
肯定很棘手。
幸运的是, Java Concurrency API为此类事情提供了一些非常直观的出色控制对象。 特别要看一下CyclicBarrier
和CountDownLatch
; 几乎可以肯定其中之一就是您要寻找的东西。
您可能还会发现ThreadPoolExecutor
在这种情况下很方便。
这是您的代码段的一个简单示例/转换,它产生以下输出(当然没有死锁):
读取行:1行
等待工作完成:1号线
在线工作:1号线
在线工作:1号线
读取行:第2行
等待工作完成:2号线
在线工作:2号线
在线工作:2号线
读线:第3行
等待工作完成:3号线
在线工作:3号线
在线工作:3号线
所有工作完成!
public class Runner
{
public static void main(String args[]) {
Runner r = new Runner();
try {
r.dowork();
} catch (IOException e) {
// handle
e.printStackTrace();
}
}
CyclicBarrier barrier;
ExecutorService executor;
private int totalWorkers = 2;
public Runner() {
this.barrier = new CyclicBarrier(this.totalWorkers + 1);
this.executor = Executors.newFixedThreadPool(this.totalWorkers);
}
public synchronized void dowork() throws IOException
{
//<code for opening a file here, other setup here, etc>
//BufferedReader reader = null;
//String line;
final Worker worker = new Worker();
for(String line : new String[]{"Line 1", "Line 2", "Line 3"})
//while ((line = reader.readLine()) != null)
{
System.out.println("Read line: " + line);
//<a large amount of processing on 'line'>
for(int c = 0; c < this.totalWorkers; c++) {
final String curLine = line;
this.executor.submit(new Runnable() {
public void run() {
worker.doWork(curLine);
}
});
}
try {
System.out.println("Waiting for work to be complete on line: " + line);
this.barrier.await();
} catch (InterruptedException e) {
// handle
e.printStackTrace();
} catch (BrokenBarrierException e) {
// handle
e.printStackTrace();
}
}
System.out.println("All work complete!");
}
class Worker
{
public void doWork(String line)
{
//<do work with this.data here>
System.out.println("Working on line: " + line);
try {
Runner.this.barrier.await();
} catch (InterruptedException e) {
// handle
e.printStackTrace();
} catch (BrokenBarrierException e) {
// handle
e.printStackTrace();
}
}
}
}
恕我直言,您未正确放置“ workersDone = 0”。
public synchronized void dowork()
{
// workersDone = 0;
//<code for opening a file here, other setup here, etc>
Worker a = new Worker(this);
Worker b = new Worker(this);
while ((line = reader.readLine()) != null)
{
workersDone = 0;
//<a large amount of processing on 'line'>
a.setData(line);
b.setData(line);
while (workersDone < totalWorkers)
{
wait();
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.