java - 带队列的信号量

标签 java multithreading semaphore

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个线程增加队列时,第二个线程正在等待,问题在于,如果我们从 quene 中提取对象并取消阻止,那么完成的线程将离开odt(),然后又一次快速地启动 enter()递增计数器,而唤醒的线程还递增计数器 current = 2 ,并且列表为空。

抱歉英语很不好

最佳答案

代码中有很多问题。

  • 同步:应该对可共享对象进行同步
    资源。为什么要对仅具有作用域的本地对象执行此操作
    该方法。

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


  • current和queue是独立的属性,它们应该是
    同步在一起。

  • 现在让我们指出如果您真的想使用Queue创建信号量。您不需要所有这些逻辑。您可以使用现有的Java类,例如BlockingQueue。这是实现
    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.");
    }
    }
    

    和Task使用信号灯
    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();
    }
    
    }
    

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

    关于java - 带队列的信号量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47063389/

    相关文章:

    c++ - 如何优雅地退出多线程应用程序?

    multithreading - 使用信号量不会唤醒其他进程

    C 中的组合信号量和自旋锁?

    c - 将信号量与 POSIX 共享内存一起使用时出现段错误

    java - 如何有效地进行多线程

    java - EL 和 HashMap 以及名称中的点

    java - 如何从 Java 调用具有自定义复杂对象类型作为输入参数的 Oracle PL-SQL 过程

    java - 线程池,worker既是生产者又是消费者

    java - 使用下限通配符时出现编译错误

    c++ - 线程池的计时测试 : single thread vs callback tp vs future tp