【问题标题】:Binary Semaphore not working if release() comes before acquire()如果 release() 在 acquire() 之前,二进制信号量不起作用
【发布时间】:2017-08-24 02:52:21
【问题描述】:

我正在编写一个测试代码,我发现如果我们将release() 放在acquire() 之前,那么二进制信号量功能就会被破坏。

我检查并发现不止一个线程通过acquire() 并将计数增加到 N,其中 N 是线程数,因此与二进制信号量相矛盾。

import java.util.concurrent.Semaphore;

/**
 * Consider an ATM cubicle with 1 ATM, Semaphore can make sure only 1 person
 * can access simultaneously.
 * 
 * Here if relese() comes before then this binary semaphore is not working.
 */
public class SemaphoreTest {

    // max 4 people
    static Semaphore semaphore = new Semaphore(1);

    public static void main(String[] args) {

        System.out.println("Total available Semaphore permits : " + semaphore.availablePermits());

        MyATMThread t1 = new MyATMThread("A",semaphore);
        t1.start();

        MyATMThread t2 = new MyATMThread("B",semaphore);
        t2.start();

        MyATMThread t3 = new MyATMThread("C",semaphore);
        t3.start();

        MyATMThread t4 = new MyATMThread("D",semaphore);
        t4.start();

        MyATMThread t5 = new MyATMThread("E",semaphore);
        t5.start();

        MyATMThread t6 = new MyATMThread("F",semaphore);
        t6.start();

    }
}

class MyATMThread extends Thread {

    String name = "";
    Semaphore semaphore = null;

    MyATMThread(String name,Semaphore s) {
        this.name = name;
        this.semaphore=s;
    }

    public void run() {

        try {

            System.out.println(name + " : acquiring lock...");
            System.out.println(name + " : available Semaphore permits now: " + semaphore.availablePermits());
            semaphore.release();
            semaphore.acquire();
            System.out.println(name + " : got the permit!");

            try {

                for (int i = 1; i <= 5; i++) {

                    System.out.println(name + " : is performing operation " + i + ", available Semaphore permits : "
                            + semaphore.availablePermits());

                    // sleep 1 second
                    Thread.sleep(1000);

                }

            } finally {

                // calling release() after a successful acquire()
                System.out.println(name + " : releasing lock...");
                semaphore.release();
                System.out.println(name + " : available Semaphore permits now: " + semaphore.availablePermits());

            }

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

}

有人可以解释这种行为吗?

【问题讨论】:

    标签: java multithreading semaphore binary-semaphore


    【解决方案1】:

    是的,您通过在获取之前发布(增加许可)来编写损坏的代码(至少按照您的预期)。这是完全有效的,但如果您打算拥有一个许可证,则不应通过在acquire() 之前调用release() 来增加它们。

    Semaphore 允许您增加超出初始数量的许可。这可以用于例如节流。工作线程将执行acquire()/release(),并且限制器将根据某些逻辑减少/增加许可。

    【讨论】:

    • 出于好奇,很想知道为什么信号量的开发者允许这样做,因为在获取之前释放锁总是会导致错误状态。
    • 增加许可并没有错。您的代码导致错误状态,但这不是信号量的错。您选择在acquire() 之前调用release()
    • 谢谢@Kayaman,您能否举一个简单的例子,我们可以在获取之前使用 release() 以便我可以更准确地理解这种行为。
    • 另外代码在每个线程中释放信号量2次,只获取一次,这也被破坏了。最初将信号量设置为 0 并从发布开始对于需要它的用例是完全有效的,例如实现某种 ManualResetEvent:释放信号量将允许获取线程继续进行。
    • 典型的例子是一个线程池,许多线程在一个空信号量上等待工作到达队列。 10 个线程可能会出现并向队列发布 10 个工作请求,每个线程向信号量释放一个单元(其计数为 10)。然后工作线程获取单元并出列工作,降低计数,直到所有工作完成,计数再次为 0,工作线程再次等待信号量:在获取之前释放。
    【解决方案2】:

    release() 方法用于增加许可,因为来自文档:

    没有要求释放许可的线程必须 已通过调用获取获得该许可。 a的正确使用 信号量是由应用程序中的编程约定建立的。

    换句话说:

    semaphore.release(10),将在当前许可的基础上再增加 10 个许可

    【讨论】:

      【解决方案3】:

      如果该线程之前没有从该Semaphore 获得许可,您可以将release() 视为“创建”另一个许可。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-29
        • 2015-11-16
        • 1970-01-01
        • 2021-08-14
        • 2012-10-07
        • 2020-12-23
        • 1970-01-01
        • 2017-10-03
        相关资源
        最近更新 更多