Java并发:排队队列问题
我正在尝试从'信号量小书'中为'排队'问题编写一个解决方案。 问题描述如下:Java并发:排队队列问题
想象一下,线程代表舞厅舞者,两种舞者,领导者和追随者在进入舞池前排队等候。领导到达时,会检查是否有追随者在等待。如果是这样,他们都可以继续。否则它会等待。同样,当追随者到达时,它会检查领导者,并相应地收益或等待。此外,还有一个限制,即每个领导者可以只与一个跟随者同时调用舞蹈,反之亦然。
书中提到它是使用信号量的解决方案,但我试图用Java中的对象锁来解决它。这里是我的解决方案:
ExclusiveQueuePrimitive.java:
import java.util.ArrayList; import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ExclusiveQueuePrimitive {
public static void main(String[] args) throws InterruptedException {
System.out
.println("-------------------------------Application START-------------------");
final int NUM_RUN = 1000;
// for (int j=0; j<NUM_RUN; j++) {
for (;;) {
Counters c = new Counters();
int NUM_THREADS = 5;
List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < NUM_THREADS; i++) {
Thread tl = new Thread(new Leader(c, i + 1));
Thread tf = new Thread(new Follower(c, i + 1));
threads.add(tf);
threads.add(tl);
tf.start();
tl.start();
}
for (int i = 0; i < threads.size(); i++) {
Thread t = threads.get(i);
t.join();
}
}
// System.out.println("--------------------------------Application END-------------------");
}
}
class Counters { public int leaders = 0;
public int followers = 0;
//public final Lock countMutex = new ReentrantLock();
public boolean printed = false;
public Lock printLock = new ReentrantLock();
public final Lock leaderQueue = new ReentrantLock();
public final Lock followerQueue = new ReentrantLock();
public void dance(String str) {
System.out.println("" + str);
}
public void printLine() {
System.out.println("");
}
}
class Leader implements Runnable { final Counters c;
final int num;
public Leader(Counters counters, int num) {
this.c = counters;
this.num = num;
}
@Override
public void run() {
synchronized (c.leaderQueue) {
try {
if (c.followers > 0) {
c.followers--;
synchronized (c.followerQueue) {
c.followerQueue.notify();
}
} else {
c.leaders++;
c.leaderQueue.wait();
}
c.dance("Leader " + num + " called dance");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Follower implements Runnable { final Counters c;
final int num;
public Follower(Counters counters, int num) {
this.c = counters;
this.num = num;
}
@Override
public void run() {
synchronized (c.followerQueue) {
try {
if (c.leaders > 0) {
synchronized (c.leaderQueue) {
c.leaders--;
c.leaderQueue.notify();
}
} else {
c.followers++;
c.followerQueue.wait();
}
c.dance("Follower " + num + " called dance");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
但是,运行一段时间后,就挂断了电话。你能告诉我死锁在哪里,我怎么修复它。另外,我想在Leader和Follower对完成后打印一个新行。我怎样才能做到这一点?
回答:
你在c.followerQueue
上有一个互斥体,在c.leaderQueue
上有一个互斥体。一方面你首先获得领导者队列,然后获得追随者队列,另一方面你首先获得追随者队列。
这很糟糕。如果一侧抓住从动锁,另一侧抓住导向锁,则两者都不能继续。您必须避免锁定采购的顺序不一致。
要在每对完成后打印一行,只需在领导者或跟随者中打印,但不能同时打印。为领导整理的代码意味着追随者已经完成也...
回答:
这是一个典型的僵局:
class Leader { synchronized (c.leaderQueue) { ...
synchronized (c.followerQueue) { ... }
}
}
class Follower {
synchronized (c.followerQueue) { ...
synchronized (c.leaderQueue) { ... }
}
}
防止最简单的事情就是抓住以相同的顺序锁(顺便说一句使用Lock
和在一起不是一个好习惯)。还有其他一些技术可以检测死锁,但是在任务环境中,更改算法应该更有利。
开始很简单 - 使用单一锁来使逻辑正确,然后做更聪明的事情来提高并发性而不破坏正确性。
以上是 Java并发:排队队列问题 的全部内容, 来源链接: utcz.com/qa/264112.html