【问题标题】:Semaphore to control access over the shared resource信号量控制对共享资源的访问
【发布时间】:2021-01-24 06:34:03
【问题描述】:

我有一个用例,我正在为用户实现对 ATM 机的访问,使用 java.util.concurrent 包中的 Semaphore 类作为锁,即锁定对资源的访问。

任何想要访问锁定的资源的线程在访问资源之前调用acquire()方法,获取锁并通过调用release()方法释放锁,完成后任务。

实施代码:

import java.util.concurrent.Semaphore;

class ATMMachine {
    
    public static void main(String []args) {
        Semaphore machines = new Semaphore(1,true);
        new Person(machines, "A");
        new Person(machines, "B");
        new Person(machines, "C");
    }
}

class Person extends Thread {
    
    private Semaphore machines;
    
    public Person(Semaphore machines, String name) {
        this.machines = machines;
        this.setName(name);
        this.start();
    }
    
    public void run() {
        try {
            System.out.println(getName()+ " is waiting to access the ATM machine");
            machines.acquire();
            System.out.println(getName()+ " is accessing the ATM machine");
            Thread.sleep(1000);
            System.out.println(getName()+ " is done using the ATM machine");
            machines.release();
        } catch(InterruptedException ie) {
            System.err.println(ie);
        }
    }
}

输出:

A is waiting to access the ATM machine
C is waiting to access the ATM machine
B is waiting to access the ATM machine
A is accessing the ATM machine
A is done using the ATM machine
C is accessing the ATM machine
C is done using the ATM machine
B is accessing the ATM machine
B is done using the ATM machine

问题:每次我运行程序时,输出都会发生变化。但是,我想确保按顺序向用户授予对机器的访问权限:A → 然后 B → 最后是 C

注意:我在构造函数中设置了fair参数为true,这应该保证FIFO按照线程被请求的顺序。但这似乎不起作用。

请求您帮助我解决问题的任何建议/参考。谢谢!

【问题讨论】:

    标签: java multithreading java-8 concurrency semaphore


    【解决方案1】:

    问题是你没有控制每个线程调用.acquire 的顺序——你只是启动了 3 个线程并且首先调用“公平”.acquire 的线程将获胜。有时是 A,有时是 B,有时是 C。

    另请注意,“FIFO 保证”可能没有您想象的那么强大——这实际上并不是关于调用 .acquire 的顺序本身,而是该函数中的一个排序点。

    所以如果你需要 A,然后是 B,然后是 C,信号量不是正确的解决方案。如果您需要以特定顺序对资源进行顺序访问,那么为什么不简化所有内容并使用单个线程处理所有内容?

    【讨论】:

    • 谢谢!这是有见地的。实际上,我正在阅读有关信号量的信息,并考虑使用它来实现用例。但正如你所说,单线程可以达到目的,而且更贴切。
    • 您可以使用信号量但不使用线程。
    【解决方案2】:

    这类需要保持线程请求访问共享资源的严格顺序的问题,是信号量/互斥量无法解决的。 您需要实现一种锁定机制,该机制将支持 FIFO 顺序以授予对共享资源的访问权限。让我们将此锁定机制称为 FIFO Mutex。您可以使用Ticket Locks 实现此FIFO 互斥锁。

    我已经为 FIFO 互斥体实现了伪代码。它可能会帮助你。在这里结帐: https://codeistry.wordpress.com/2018/03/21/fifo-mutex/

    FIFO Mutex 类的伪代码:

    class FifoMutex
    {
    public:
     
        FifoMutex();
        ~FifoMutex();
        void
        lock();
        void
        unlock();
     
    private:
     
        UINT32 m_nowServing;
        UINT32 m_nextAvailable;
        ConditionMutex *m_condMutex;
    };
     
    FifoMutex::FifoMutex()
    {
        m_nowServing = 0;
        m_nextAvailable = 0;
        m_condMutex = new ConditionMutex();
    }
    void
    FifoMutex::lock()
    {
        UINT32 myTicket;
     
        // Get your ticket and increment the m_nextAvailable.
        m_condMutex->lock();
            myTicket = m_nextAvailable;
            m_nextAvailable++;
        m_condMutex->unlock();
     
        // Wait till your ticket is getting served.
        m_condMutex->lock();
            while (m_nowServing != myTicket) {
                m_condMutex->wait();
            }
        m_condMutex->unlock();
    }
     
    void
    FifoMutex::unlock()
    {
        // Increment the m_nowServing and wakeup all blocked threads.
        m_condMutex->lock();
            m_nowServing++;
            // Pl note we are broadcasting the wakeup call.
            // We must broadcast since we don't know 
            // which thread should acquire the lock next.
            // All the waiting threads will be unblocked, 
            // only one of them will pass condition: "m_nowServing == myTicket"
            m_condMutex->broadcast();
        m_condMutex->unlock();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-03
      • 1970-01-01
      • 2023-03-10
      • 2015-06-07
      • 1970-01-01
      • 1970-01-01
      • 2021-02-05
      • 1970-01-01
      相关资源
      最近更新 更多