【デザインパターン】【非同期】Balking パターン

Balking パターン

 * Balking (ボーキング)
 ⇒Balk「ボーク」(野球のボークと同じで、投球動作を「途中でやめる」)
 * balk(ボーク) = 「急に止まる」「妨げる」「裏をかく」
 * ざっくり言うと、「ブロック」。

使いどころ

 * 別スレッドが処理していたら、処理を実行せずに返す場合
 * オブジェクトの状態が不都合な時に、処理を実行したくない場合

構文

private volatile boolean isWorking = false;
void execute() {
    synchronized (this) {
        if (isWorking) {
            // !実行中(isWorking = true)は弾く様にする!
            return;
        }
        isWorking = true;
    }
    // do something
    isWorking = false;
}

補足

 * ReentrantLock を使えば、スマートにできる?
http://blogs.yahoo.co.jp/dk521123/34254262.html

サンプル

Main.java

public class Main {

   public static void main(String[] args) {
      Task task = new Task();
      
      Worker worker1 = new Worker(task);
      worker1.start();
      
      Worker worker2 = new Worker(task);
      worker2.start();
      
      Worker worker3 = new Worker(task);
      worker3.start();
   }
}

Task.java

import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;

public class Task {
   private Random random = new Random();
   private AtomicBoolean isWorking = new AtomicBoolean(false);

   public void execute() {
      synchronized (this) {
         if (this.isWorking.get()) {
            System.out.println("    Balk : " + Thread.currentThread().getName());
            return;
         }
         this.isWorking.set(true);
      }
      this.heavyWork();
      this.isWorking.set(false);
   }

   private void heavyWork() {
      System.out.println("Start :" + Thread.currentThread().getName());
      try {
         Thread.sleep(random.nextInt(5000));
      } catch (InterruptedException ignore) {
      }
      System.out.println("Done :" + Thread.currentThread().getName());

   }
}

Worker.java

import java.util.Random;

public class Worker extends Thread {
   private Random random = new Random();
   private Task task;
   public Worker(Task task) {
       this.task = task;
   }
   public void run() {
      while (true) {
         task.execute();
         System.out.println("    Work : " + Thread.currentThread().getName());
         try {
            Thread.sleep(random.nextInt(5000));
         } catch (InterruptedException e) {
         }
      }
   }
}

出力結果

Start :Thread-0
    Balk : Thread-1
    Work : Thread-1
    Balk : Thread-2
    Work : Thread-2
    Balk : Thread-1
    Work : Thread-1
Done :Thread-0
    Work : Thread-0
Start :Thread-2
Done :Thread-2
    Work : Thread-2

...続く