我正在尝试同步3个线程。他们每个人都会处理沿着自己的路径移动的毛毛虫。 不幸的是他们的路径是这样的:
为了达到这个目标,我正在使用锁。共享块有两个部分:水平和垂直(我在上面和下面命名)。问题是一个点上的线程想要同时在两个共享部分中。
我的问题是:
我可以使用标志解锁try / finally子句中的锁吗?
我的意思是,当一个线程在try / finally子句中解锁一个锁时,会设置一个标志,并在finally子句中检查该标志是否已设置,然后不再解锁。我认为这是一个安全的解决方案,但也许我错了。
还有其他方法可以同步线程吗?
这是我的代码:(它几乎可以使用)
public void moveForward() throws InterruptedException {
redIsUpofAbove();
int choose= 0;
if (Route.critcalSectionAbove.contains(head))
choose= 1;
if (Route.critcalSectionBelow.contains(head))
choose= 2;
switch (choose) {
case 1: {
boolean flag = true;
System.err.println(name + " Lock above");
synchronization.aboveLock.lock();
try {
takeNextGrid();
Thread.sleep(sleepValue);
while (isInAboveCriticalSection()) {
takeNextGrid();
Thread.sleep(sleepValue);
if (isInBelowCriticalSection()) {// Caterpillar is on two
// shared sections
System.out.println(name + " Lock below");
if (!synchronization.belowLock.tryLock()) {
synchronization.aboveLock.unlock();
System.out.println(name + " Unlock above");
synchronization.belowLock.lock();
flag = false;
}
try {
while (isInBelowCriticalSection()) {
takeNextGrid();
if (!isInAboveCriticalSection() && flag) {
synchronization.aboveLock.unlock();
flag = false;
System.out.println(name + " Unlock above");
}
Thread.sleep(sleepValue);
}
} catch (Exception e) {
} finally {
synchronization.belowLock.unlock();
System.err.println(name + "Unlock belovelock");
}
}
}
} catch (Exception e) {
} finally {
if (flag) {
synchronization.aboveLock.unlock();
System.out.println(name + " unlock above");
}
}
break;
}
case 2: {
boolean flag = true;
System.err.println(name + " Lock below");
synchronization.belowLock.lock();
try {
takeNextGrid();
Thread.sleep(sleepValue);
while (isInBelowCriticalSection()) {
takeNextGrid();
Thread.sleep(sleepValue);
if (isInAboveCriticalSection()) {
if (!synchronization.aboveLock.tryLock() && flag) {
synchronization.belowLock.unlock();
System.out.println(name + " Unlock below");
synchronization.aboveLock.lock();
flag = false;
}
try {
System.out.println(name + " Lock above");
while (isInAboveCriticalSection()) {
takeNextGrid();
if (!isInBelowCriticalSection() && flag == true) {
synchronization.belowLock.unlock();
flag = false;
System.out.println(name + " Lock below");
}
Thread.sleep(sleepValue);
}
} catch (Exception e) {
} finally {
synchronization.aboveLock.unlock();
System.err.println(name + "Lock abovelock");
}
}
}
} catch (Exception e) {
} finally {
if (flag) {
synchronization.belowLock.unlock();
System.out.println("Opuszczam belowLock");
}
}
break;
}
default: {
takeNextGrid();
break;
}
}
}
最后一个问题:
有没有办法在等待锁定锁定的线程上设置唤醒优先级?
答案 0 :(得分:3)
我可以使用标志解锁try / finally子句中的锁吗?
假设您在InterruptException
电话和设置标志之间没有lock()
,那么这应该正常工作;但是,我认为在给定的背景下它没有任何意义。
如果您遇到异常,毛毛虫会怎么样?它消失了吗?如果它仍然位于路径上的相同位置,即使在之后抛出异常,那么它仍然占据路径的那一部分;因此,释放锁是没有意义的。
还有其他方法可以同步线程吗?
你可以尝试其他同步机制(原子,监视器锁等),但这似乎不是一个性能关键的应用程序,所以我只会使用任何使得最有意义的。如果锁是有意义的,那么使用锁。
现在,如果您在询问是否有不同的方式进行同步(例如,用于路径上的互斥的不同策略),那么我确实有一个建议:< / p>
您当前的解决方案存在明显的死锁问题。由于below
和above
部分是单独获得的,蓝色毛毛虫(G2,“蓝色”)可以获得下部并且同时移入红色毛虫(G1,“红色“)可以获得上部并进入。现在任何一条卡特彼勒都无法完成其路径 - 它们已陷入僵局(G1将无法前进到下部,而G2将无法进入上部)。
通过将路径拆分为更重要的部分(如我的图像所示),并在移动到关键部分时获取多个部分,那么您可以避免这种死锁情况。
只要你确保“临界T”中最多有2只毛毛虫(即所有4个关键区域的联合),那么你总能避免死锁。您可以通过创建具有2个许可的counting semaphore来完成此操作。您在获取路径中第一个关键区域的锁定之前acquire()
,并在离开该区域后的某个时间release()
。例如,对于Red,序列将是:
acquire()
关于sempahore lock()
上方,并通过它前进lock()
左下方release()
unlock()
上方unlock()
左下方请注意,我们不需要显式锁定Center,因为它被信号量和其他锁隐式保护。
显然,您可以使用其他方法来确保“临界T”中只有2条毛毛虫,但信号量似乎是最简单的方法。
此解决方案可以避免死锁,如下所示:
所有其他可能的配置也将避免死锁 - 这只是三个最有趣的案例。
有没有办法在等待锁定锁定的线程上设置唤醒优先级?
我不知道Java库中的任何工具实际上会给你这样的优先保证。您要么必须找到执行此操作的第三方库,要么实现自己的。
一个简单的方法就是不要为你的毛毛虫使用单独的线程。您可以使用单个线程完成所有Caterpillar逻辑 - 没有理由为每个Caterpillar都需要一个线程。如果您在一个线程中拥有所有逻辑,那么您处理毛毛虫的顺序将为您提供隐式优先级排序。
答案 1 :(得分:1)
DaoWen的算法运作良好。 这是红色毛毛虫的代码,其他毛毛虫的作品 同样的原则,变化很小。我将路径分为三个关键部分:上方,左下方,右下方。中心区域有助于定义毛毛虫何时离开临界区域然后解锁织锦。信号量保证最多两个线程可以请求进入关键部分。在方法结束之前,标志对于解锁bloc非常有用,并且只提供一次blocade unococed。
public final ReentrantLock aboveLock = new ReentrantLock(true);
public final ReentrantLock LeftBelowLock = new ReentrantLock(true);
public final ReentrantLock RightBelowLock = new ReentrantLock(true);
public final Semaphore semaphore = new Semaphore(2); //counting semaphore
private void movingRed() throws InterruptedException {
while (true) {
if (Route.critcalSectionAbove.contains(head)) {
synchronization.semaphore.acquireUninterruptibly();
synchronization.aboveLock.lock();
isAboveLock = true;
synchronization.LeftBelowLock.lock();
isBelowLeftLock = true;
synchronization.semaphore.release();
try {
while (!ifTailLeftCenter()) { // advance Critical-region
// until tail crosses center
takeNextGrid();
Thread.sleep(sleepValue);
}
// caterpillar's tail left Center section
isAboveLock = false;
synchronization.aboveLock.unlock(); // unclocking above
while (isInBelowCriticalSectionLeft()) { // advance until
// tail belong
// to Left-Below
takeNextGrid();
Thread.sleep(sleepValue);
}
// caterpillar's tail left LeftBelow section
isBelowLeftLock = false;
synchronization.LeftBelowLock.unlock();
} catch (Exception e) {
} finally {
if (isAboveLock)
synchronization.aboveLock.unlock(); // in case exception
// was throw before
// unlock any lock
if (isBelowLeftLock)
synchronization.LeftBelowLock.unlock();
}
}
// caterpillar moving through non-critical region
takeNextGrid();
Thread.sleep(sleepValue);
}
}
感谢您的帮助。