【发布时间】:2012-11-25 15:06:58
【问题描述】:
我需要两个线程来编写一个共享整数数组。两个线程都需要写入该数组的所有元素。每个线程将写入 1 或 7,结果应类似于 171717171(或 71717171)。为此,我将第一个 Thread1 写入位置 0,然后等待。 Thread2 现在写入位置 0 和 1,通知 Thread1,然后等待。 Thread1 在位置 1 和 2 写入,通知 Thread2 并等待,等等。使用以下代码,我得到正确的输出,尽管使用 JPF 运行时发现死锁。它变得非常令人沮丧,因为我找不到它有什么问题。任何意见,将不胜感激。
import java.util.logging.Level;
import java.util.logging.Logger;
public class WriterThreadManager {
private int[] array = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
private Thread thread7;
private Thread thread1;
public static void main(String[] args) {
WriterThreadManager mng = new WriterThreadManager();
mng.exec();
}
public WriterThreadManager() {
thread7 = new Thread(new WriterRunnable(this, 7));
thread1 = new Thread(new WriterRunnable(this, 1));
}
public void overwriteArray(int pos, int num) {
array[pos] = num;
printArray();
}
private void printArray() {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]);
}
System.out.println("");
}
public synchronized void stopThread() {
try {
this.wait();
} catch (InterruptedException ex) {
Logger.getLogger(WriterThreadManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public synchronized void wakeUpThread() {
notifyAll();
}
private void exec() {
thread7.start();
thread1.start();
}
public int length() {
return array.length;
}
}
public class WriterRunnable implements Runnable {
private WriterThreadManager mng;
private int numberToWrite;
private static boolean flag = true;
@Override
public void run() {
int counter = 0;
int j = 0;
//first thread to get in should write only at
//position 0 and then wait.
synchronized (mng) {
if (flag) {
flag = false;
mng.overwriteArray(0, numberToWrite);
j = 1;
waitForOtherThread();
}
}
for (int i = j; i < mng.length(); i++) {
mng.overwriteArray(i, numberToWrite);
counter++;
if (i == mng.length() - 1) {
mng.wakeUpThread();
break;
}
if (counter == 2) {
waitForOtherThread();
counter = 0;
}
}
}
private void waitForOtherThread() {
mng.wakeUpThread();
mng.stopThread();
}
public WriterRunnable(WriterThreadManager ar, int num) {
mng = ar;
numberToWrite = num;
}
}
ps:执行示例:
1000000000
7000000000
7700000000
7100000000
7110000000
7170000000
7177000000
7171000000
7171100000
7171700000
7171770000
7171710000
7171711000
7171717000
7171717700
7171717100
7171717110
7171717170
7171717177
7171717171
来自 JPF 的错误快照如下:
thread java.lang.Thread:{id:1,name:Thread-1,status:WAITING,priority:5,lockCount:1,suspendCount:0}
waiting on: WriterThreadManager@152
call stack:
at java.lang.Object.wait(Object.java)
at WriterThreadManager.stopThread(WriterThreadManager.java:43)
at WriterRunnable.waitForOtherThread(WriterRunnable.java:53)
at WriterRunnable.run(WriterRunnable.java:45)
thread java.lang.Thread:{id:2,name:Thread-2,status:WAITING,priority:5,lockCount:1,suspendCount:0}
waiting on: WriterThreadManager@152
call stack:
at java.lang.Object.wait(Object.java)
at WriterThreadManager.stopThread(WriterThreadManager.java:43)
at WriterRunnable.waitForOtherThread(WriterRunnable.java:53)
at WriterRunnable.run(WriterRunnable.java:45)
【问题讨论】:
-
是否要求严格依次进行写入?这似乎是使用信号量的经典案例。
-
好吧,您在 3 个不同的对象(管理器和两个可运行对象)上进行同步。您不会在检查条件的循环内等待()。并且对数组的每次访问都不同步。绝对使用更高级别的抽象(例如信号量)来同步您的线程。
-
既然是功课,OP可能会受限于他能用的东西。
-
@Perception 我只熟悉信号量的概念,并不熟悉 Java 中的具体实现。关于轮流写入:由于两个线程都需要在数组中的每个位置写入,这是我找到的唯一解决方案。
-
@Giannis JB Nizet 的 cmets 确实适用,即使您坚持解决问题的低级方法(不同的显示器、等待时没有循环、缺乏同步......)
标签: java multithreading jpf