信号量与队列

时间:2017-11-01 20:45:54

标签: 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 中提取对象并取消阻止它,那么完成的线程将离开()更快地开始输入()并再次增加计数器,而唤醒的线程也会增加计数器 current = 2 ,列表为空。

对不良英语抱歉

1 个答案:

答案 0 :(得分:0)

代码中存在许多问题。

  1. 同步:应该对可共享进行同步 资源。为什么只对具有范围的本地对象执行此操作 那种方法。
  2.   

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

    1. 当前和队列都是独立的属性,它们应该是 同步在一起。
    2. 现在让我们来指出如果你真的想用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.");
      }
      }
      

      使用信号量的任务

      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来创建Semaphores,因为它通过在队列中创建元素来浪费内存。尽管如此,您可以使用单个可共享对象创建信号量,并允许使用等待和通知机制。你可以尝试这种方法。如果你愿意的话。