线程 - 使用标志解锁并尝试/终止

时间:2016-05-30 12:57:42

标签: java multithreading synchronize locks

我正在尝试同步3个线程。他们每个人都会处理沿着自己的路径移动的毛毛虫。 不幸的是他们的路径是这样的: image

为了达到这个目标,我正在使用锁。共享块有两个部分:水平和垂直(我在上面和下面命名)。问题是一个点上的线程想要同时在两个共享部分中。

我的问题是:

我可以使用标志解锁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;
    }
    }

}

最后一个问题:

有没有办法在等待锁定锁定的线程上设置唤醒优先级?

2 个答案:

答案 0 :(得分:3)

  

我可以使用标志解锁try / finally子句中的锁吗?

假设您在InterruptException电话和设置标志之间没有lock(),那么这应该正常工作;但是,我认为在给定的背景下它没有任何意义。

如果您遇到异常,毛毛虫会怎么样?它消失了吗?如果它仍然位于路径上的相同位置,即使之后抛出异常,那么它仍然占据路径的那一部分;因此,释放锁是没有意义的。

  

还有其他方法可以同步线程吗?

你可以尝试其他同步机制(原子,监视器锁等),但这似乎不是一个性能关键的应用程序,所以我只会使用任何使得最有意义的。如果锁是有意义的,那么使用锁。

现在,如果您在询问是否有不同的方式进行同步(例如,用于路径上的互斥的不同策略),那么我确实有一个建议:< / p>

caterpillar tracks with 4 critical sections

您当前的解决方案存在明显的死锁问题。由于belowabove部分是单独获得的,蓝色毛毛虫(G2,“蓝色”)可以获得下部并且同时移入红色毛虫(G1,“红色“)可以获得上部并进入。现在任何一条卡特彼勒都无法完成其路径 - 它们已陷入僵局(G1将无法前进到下部,而G2将无法进入上部)。

通过将路径拆分为更重要的部分(如我的图像所示),并在移动到关键部分时获取多个部分,那么您可以避免这种死锁情况。

只要你确保“临界T”中最多有2只毛毛虫(即所有4个关键区域的联合),那么你总能避免死锁。您可以通过创建具有2个许可的counting semaphore来完成此操作。您在获取路径中第一个关键区域的锁定之前acquire(),并在离开该区域后的某个时间release()。例如,对于Red,序列将是:

  1. acquire()关于sempahore
  2. lock()上方,并通过它前进
  3. lock()左下方
  4. 信号量
  5. release()
  6. 继续前进到中心然后进入左下方
  7. 一旦Red的尾巴离开中心,unlock()上方
  8. 一旦红色的尾巴离开左下方,unlock()左下方
  9. 继续推进非关键区域......
  10. 请注意,我们不需要显式锁定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);
    }
}

感谢您的帮助。