带队列的信号量

Semaphore with queue

public class SemaphoreWithQueues  implements Semaphore {
    private List<Object> queue;
    private AtomicInteger current = new AtomicInteger(0);
    private int permits;

    public SemaphoreWithQueues(int permits) {
        this.permits = permits;
        this.queue = Collections.synchronizedList(new LinkedList<>());
    }

    @Override
    public void enter() throws InterruptedException {
        if (current.get() < permits) {
           current.incrementAndGet();
        } else {
            Object block = new Object();
            synchronized (block) {
                queue.add(block);
                block.wait();
                current.incrementAndGet();
            }
        }
    }

    @Override
    public void leave() {
        if(queue.size() != 0) {
            Object block = queue.get(0);
            queue.remove(0);
            synchronized (block) {
                block.notify(); //Unblock quenue
            }
        }
        current.decrementAndGet();
        //current lessen and current thread have time come in block if(...)
        // in enter() faster then another thread increased current
    }
}

> The program usually output: 
> 
> 1 1 2 2 1 1 2 2 1 2

**Where run() of both threads is almost the same, such as:**


     public void run(){
                for (int i = 0; i <5; i++) {
                    try {
                        semaphore.enter();
                    } catch (InterruptedException e) {
                        System.err.println(e);
                    }
                    System.out.println(2);
                    semaphore.leave();

                }
            }

有 2 个线程使用此信号量。当1个线程增加queue时,第二个在等待,问题是如果我们从quene中提取对象并解除阻塞,那么线程完成 leave() 更快地启动 enter() 并再次递增 counter,同时唤醒线程还增加了 countercurrent = 2,列表为空。

抱歉英语不好

代码中有很多问题。

  1. 同步:应为可共享的内容进行同步 资源。为什么它是为一个只具有范围的本地对象完成的 那个方法。

Object block = new Object(); synchronized (block) {

  1. current和queue都是独立的属性,应该是 一起同步。

现在让我们来点如果你真的想用Queue创建一个信号量。您不需要所有这些逻辑。您可以使用现有的 Java class 例如阻塞队列。这是实现

class SemaphoreWithQueues implements Semaphore{
private BlockingQueue<Integer> queue;

public SemaphoreWithQueues(int permits) {
    if(queue == null){
        queue = new ArrayBlockingQueue<>(permits);
    }
}

public void enter() {
    queue.offer(1);
    System.out.println(Thread.currentThread().getName() + " got a permit.");
}

public void leave() throws InterruptedException {
    queue.take();
    System.out.println(Thread.currentThread().getName() + " left the permit.");
}
}

和任务使用信号量

class Task implements Runnable {
private SemaphoreWithQueues semaphore;
public Task(SemaphoreWithQueues semaphore){
    this.semaphore = semaphore;
}

public void run(){
    for (int i = 0; i <5; i++) {
        semaphore.enter();
        try {
            semaphore.leave();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

}
public class Main {
public static void main(String[] args) {
    SemaphoreWithQueues semaphoreWithQueues = new SemaphoreWithQueues(5);
    Thread th1 = new Thread(new Task(semaphoreWithQueues));
    Thread th2 = new Thread(new Task(semaphoreWithQueues));
    Thread th3 = new Thread(new Task(semaphoreWithQueues));
    th1.start();
    th2.start();
    th3.start();
}

}

但我个人不喜欢使用队列来创建信号量,因为它通过在队列中创建元素来浪费不必要的内存。尽管如此,您可以使用等待和通知机制的许可使用单个可共享对象创建信号量。您可以尝试使用这种方法。如果你愿意。