2017-11-01 6 views
0
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とブロックされていないからオブジェクトを抽出した場合、それは、休暇を()終了後、スレッドはより速く、再び)(が入り始めるということですカウンタをに増やし、awakeスレッドはカウンタを,現在= 2とインクリメントし、リストは空です。キューを持つセマフォ

BAD ENGLISH FOR SORRY

+0

'if(current

+0

intをAtomicIntegerに変更しましたが、これで問題は解決しませんでした。 – Youlfey

+0

'AtomicInteger'は、別のスレッドが比較' current

答えて

0

コードには多くの問題があります。

  1. 同期:共有可能な共有 リソースに対して同期を行う必要があります。その方法の範囲が のローカルオブジェクトに対して行われるのはなぜですか。

オブジェクトブロック=新しいオブジェクト(); 同期(ブロック){

  • 現在およびキューが独立プロパティは、それらが一緒に同期 であるべきです。
  • ここで、実際にキューを使用してセマフォを作成する場合は、ここをクリックしてください。あなたはこのすべてのロジックを必要としません。たとえば、既存の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(); 
    } 
    
    } 
    

    を使用することである。しかし、それはキュー内の要素を作成することで、不要なメモリを浪費として個人的に私は、セマフォを作成するためにキューを使用して好きではありません。それにもかかわらず、待機および通知メカニズムを使用して許可を持つ単一の共有可能オブジェクトを使用してセマフォを作成できます。このアプローチで試すことができます。もしよければ。

    関連する問題