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

回到顶部