【问题标题】:Non-reentrant non-blocking semaphore in JavaJava中的非可重入非阻塞信号量
【发布时间】:2018-02-22 18:14:06
【问题描述】:

我需要一个具有以下特性的信号量:

  1. 它应该是非阻塞的,即如果线程无法获得许可 它应该更进一步,无需等待
  2. 它应该是不可重入的,即如果同一个线程进入 保护一段代码两次它应该拿走两个许可证而不是 一个

我写了以下代码:

public class SimpleSemaphore
{

    private int permits;

    private AtomicLong counter = new AtomicLong();

    SimpleSemaphore(int permits)
    {
        this.permits = permits;
    }

    boolean acquire()
    {

        if (counter.incrementAndGet() < permits)
        {
            return true;
        }
        else
        {
            counter.decrementAndGet();
            return false;
        }

    }

    void release()
    {
        counter.decrementAndGet();

    }
}

另一个选项是这个信号量:

public class EasySemaphore
{

    private int permits;

    private AtomicLong counter = new AtomicLong();

    EasySemaphore(int permits)
    {
        this.permits = permits;
    }

    boolean acquire()
    {
        long index = counter.get();

        if (index < permits)
        {
            if (counter.compareAndSet(index, index + 1))
            {
                return true;
            }
        }

        return false;
    }

    void release()
    {
        counter.decrementAndGet();
    }
}

这两种实现都是线程安全且正确的吗? 哪一个更好? 您将如何完成这项任务?

【问题讨论】:

    标签: java concurrency semaphore nonblocking


    【解决方案1】:

    java.util.concurrent.Semaphore 不是已经做了所有这些了吗?

    它有一个用于非阻塞获取的tryAcquire,它维护一个简单的剩余许可计数(同一个线程可以取出多个许可)。

    【讨论】:

    • 真的,tryAcquire 方法正是我所需要的,谢谢!但是 java.util.concurrent.Semaphore 的重入呢?我在文档中找不到任何证据表明一个线程可能会获得许多许可。
    • 它在文档中说没有所有权跟踪,只是一个简单的计数器,并且信号量可以从与获取它的线程不同的线程中释放。我认为您的要求由此而来。
    【解决方案2】:

    我会说第二个更好,因为计数器永远不会大于 0(并且效率略高)

    我会使用循环,否则当仍有许可时,您可能会导致方法失败。

    public class EasySemaphore {
        private final AtomicInteger counter;
    
        EasySemaphore(int permits) {
            counter = new AtomicInteger(permits);
        }
    
        boolean acquire() {
            // highly unlikely to loop more than once.
            while(true) {
                int count = counter.get();
                if (count <= 0) return false;
                if (counter.compareAndSet(count, count -1)) 
                    return true;
            }
        }
    
        void release() {
            counter.incrementAndGet();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-04
      • 2014-09-25
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多