我有两个线程,T1和T2。两者都有自己的数组列表,我想从T1中删除数组列表中的一个元素,并且在删除之后,我希望它除非要删除T2数组列表元素
这就是流程应该如何:
t1 remove element
t2 remove element
t1 remove element
t2 remove element
.
.
.
这是我的代码:
import static java.lang.Thread.sleep;
import java.util.ArrayList;
public class ThreadsTest {
public static void main(String[] args) {
Thread t1 = new Thread(new T1());
t1.start();
Thread t2 = new Thread(new T2());
t2.start();
}
}
class T1 implements Runnable {
private ArrayList<String> list;
public T1() {
list = new ArrayList();
list.add("t1 1");
list.add("t1 2");
list.add("t1 3");
list.add("t1 4");
list.add("t1 5");
}
@Override
public void run() {
while (!list.isEmpty()) {
System.out.println(list.remove(0));
try {
synchronized (this) {
wait();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
class T2 implements Runnable {
private ArrayList<String> list;
public T2() {
list = new ArrayList();
list.add("t2 1");
list.add("t2 2");
list.add("t2 3");
list.add("t2 4");
list.add("t2 5");
}
@Override
public void run() {
while (!list.isEmpty()) {
System.out.println(list.remove(0));
try {
synchronized (this) {
notifyAll();
sleep(1000);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
为什么呼叫通知不会唤醒T1?以及如何解决它?
答案 0 :(得分:2)
您的代码中存在两个问题:
首先你要在监视器上同步/等待“this”,这是实际的对象,所以在T1的情况下它是T1而在T2的情况下它是T2。要正确执行此操作,两个线程都需要同步/等待相同的对象。一种常见的方法是专门创建这样的对象:
final static Object monitor = new Object();
请注意final
关键字在此非常重要,您不希望在两者之间意外更改显示器。
但即使你这样做,也无法保证T2在调用notifyAll()
期间T1已经在等待,因为线程的执行顺序是未定义的。实际上,这可能导致T1在删除后的最后一次等待调用期间死锁,因为T2已经完成。
修改:如何使用Phaser
执行此操作声明两个线程都可以使用的Phaser实例:
static final Phaser phaser = new Phaser(2); // 2 threads = 2 parties
T1的运行方法变为:
while (!list.isEmpty()) {
System.out.println(list.remove(0));
phaser.arriveAndAwaitAdvance();
phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();
T2的运行方法变为:
while (!list.isEmpty()) {
phaser.arriveAndAwaitAdvance();
System.out.println(list.remove(0));
phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();
在这种情况下,取消注册不是必需的,但作为一种安全机制:一旦取消注册,系统就可以在没有完成的线程的情况下继续。