2016-11-05 14 views
0

N実行後に「同期」したいJava/Groovyマルチスレッドプロセスがある: - スレッド実行後に共有カウンタが減少する - 目標はカウンタを一度リセットすることです他のスレッドがアクセスしていない間は0になります。N個の実行後に複数のスレッドを調整する

私はReadWriteReentrantLockで試しましたが、減量段階の競合状態があるようです。ここではおそらくのAtomicInteger値の欠落している「同期」のチェックに、私のテストコード(負のカウンタ値を持つ)は、次の奇妙な出力が得られ

public static void main(String[] args) { 
    AtomicInteger counter = new AtomicInteger(Decrementer.MAX_SIZE) 
    ReadWriteLock lock = new ReentrantReadWriteLock() 

    for (int i = 1; i <= 10; i++) { 
     Decrementer d = new Decrementer(counter, lock) 
     new Thread(d).start() 
    } 
} 

public class Decrementer implements Runnable { 

    public final static int MAX_SIZE = 5 
    private ReadWriteLock lock 
    private AtomicInteger counter 

    public Decrementer(AtomicInteger counter, ReadWriteLock lock) { 
     this.counter = counter 
     this.lock = lock 
    } 

    public void run() { 
     while (true) { 
      try{ 
       lock.readLock().lock() 
       int current = this.counter.decrementAndGet() 
       System.out.println(Thread.currentThread().getName() + " at counter " + current) 
       Thread.sleep(762) 
      } finally { 
       lock.readLock().unlock() 
      } 

      try { 
       lock.writeLock().lock() 
       int current = this.counter.get() 
       if (current <= 0) { 
        this.counter.set(Decrementer.MAX_SIZE) 
        System.out.println(Thread.currentThread().getName() + " reset " + current + " to " + Decrementer.MAX_SIZE) 
        Thread.sleep(4217) 
       } 
      } finally { 
       lock.writeLock().unlock() 
      } 
     } 
    } 
} 

です。

Thread-3 at counter 2 
Thread-2 at counter 4 
Thread-1 at counter 3 
Thread-4 at counter 1 
Thread-5 at counter 0 
Thread-6 at counter -1 
Thread-7 at counter -2 
Thread-8 at counter -3 
Thread-9 at counter -4 
Thread-10 at counter -5 
Thread-2 reset -5 to 5 
Thread-3 at counter 4 
Thread-4 at counter 2 
Thread-2 at counter 3 
Thread-1 at counter 1 
Thread-5 at counter -3 
Thread-10 at counter -4 
Thread-7 at counter -1 
Thread-6 at counter -2 
Thread-8 at counter 0 
Thread-9 at counter -5 
Thread-9 reset -5 to 5 

私もCountDownLatchCyclicBarrierクラスを見ましたが、私の目標は、すべてのスレッドを同期するのではなく、カウンタリセットは、原子や他のスレッドによって、他の修正を除くであることを保証するものではありません。

私のコードで見逃していた明らかな並行性の問題はありますか?

答えて

1

ロックはその逆です。読み取りロックを取得してから、「書き込み」を実行しています。これは動作するはずです:

書き込みロックの獲得のコメントに基づいて
public static void main(String[] args) { 
    AtomicInteger counter = new AtomicInteger(Decrementer.MAX_SIZE); 
    ReadWriteLock lock = new ReentrantReadWriteLock(); 

    for (int i = 1; i <= 10; i++) { 
     Decrementer d = new Decrementer(counter, lock); 
     new Thread(d).start(); 
    } 
} 

static public class Decrementer implements Runnable { 

    public final static int MAX_SIZE = 5; 
    private ReadWriteLock lock; 
    private AtomicInteger counter; 

    public Decrementer(AtomicInteger counter, ReadWriteLock lock) { 
     this.counter = counter; 
     this.lock = lock; 
    } 

    public void run() { 
     while (true) { 
      try { 
       lock.writeLock().lock(); 
       int current = this.counter.decrementAndGet(); 
       System.out.println(Thread.currentThread().getName() + " at counter " + current); 
       if (current <= 0) { 
        this.counter.set(Decrementer.MAX_SIZE); 
        System.out.println(Thread.currentThread().getName() + " reset " + current + " to " + Decrementer.MAX_SIZE); 
        Thread.sleep(4217); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } finally { 
       lock.writeLock().unlock(); 
      } 
     } 
    } 
} 
+0

感謝を。あなたは大丈夫です:私は、読み取りロックで(カウンタに)書き込みを行っていました。 しかしあなたの解決策では、スレッドごとにWriteLockを取得しようとすると、すばやく飢餓につながります(実際に一度に1スレッドしか実行しません) 私はあなたのアドバイスをフォローアップし、書き込み部分をグループ化します(decrement + test + resetカウンタ一緒に)プロセスの読み込みロックを保持する(Sleepでシミュレート) – Wavyx

+0

これは単なる実例であり、完全な解決策ではありません。私はまた、生産にThread.sleep(4217)を使用することを強くお勧めします! :) –

0

、ここで働いている解決策:コメントを

public class Decrementer implements Runnable { 

public final static int MAX_SIZE = 20; 
private ReadWriteLock lock; 
private AtomicInteger counter; 

public Decrementer(AtomicInteger counter, ReadWriteLock lock) { 
    this.counter = counter; 
    this.lock = lock; 
} 

public void run() { 

    while (true) { 
     int current 
     try { 
      lock.writeLock().lock(); 
      if (this.counter.compareAndSet(0, Decrementer.MAX_SIZE)) { 
       current = 0; 
       flushWork(current); 
      } else { 
       current = counter.decrementAndGet(); 
       System.out.println(Thread.currentThread().getName() + " decrement " + current); 
      } 
     } finally { 
      lock.writeLock().unlock(); 
     } 

     try { 
      lock.readLock().lock(); 
      doWork(current); 
     } finally { 
      lock.readLock().unlock(); 
     } 
    } 
} 

private void flushWork(int current) { 
    System.out.println(Thread.currentThread().getName() + " reset " + current + " to " + Decrementer.MAX_SIZE); 
    System.out.println('------------------------------------------------------------------------------------'); 
    Thread.sleep(4217); 
} 

private void doWork(int current) { 
    System.out.println(Thread.currentThread().getName() + " at counter " + current); 
    Thread.sleep(62); 
} 
} 
関連する問題