EeBlog(テクニカルブログ)

第50回 シンクロナイザ編 CountDownLatch

今回のテーマは「CountDownLatch」です。

CountDownLatchは他のスレッドで実行中の操作セットが完了するまで、1 つ以上のスレッドを待機可能にする同期化支援機能です。 CountDownLatchは指定されたカウントを使用して初期化されます。 このカウントはcountDownメソッドの実行により減算し、カウントがゼロになるまでスレッドを待機させることができる仕組みになっています。

次のサンプルコードはファイルのミラーリングプログラムです。 実際は同じファイルを2つ作成しているだけです。(J2SE5.0以上対応)

import java.io.BufferedOutputStream; 
import java.io.File; 
import java.io.FileOutputStream; 
import java.util.concurrent.Callable; 
import java.util.concurrent.CountDownLatch; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors;

public class Main {

    private static final String TEXT = "abcdefghijklmnopqrstuvwxyz"; 
         
    public static void main(String[] args) throws Exception { 
        byte[] bytes = TEXT.getBytes(); 
        File[] files = { new File("output1.txt"), new File("output2.txt") }; 
        CountDownLatch countDownLatch = new CountDownLatch(files.length); 
        ExecutorService executorService = Executors.newCachedThreadPool(); 
        for (File file : files) { 
            executorService.submit(new ICallable(countDownLatch, file, bytes)); 
        } 
        executorService.shutdown(); 
        countDownLatch.await(); 
        System.out.println("END"); 
    } 
}

class ICallable implements Callable<Object> {
    private CountDownLatch countDownLatch; 
    private File file; 
    private byte[] bytes;

    public ICallable(CountDownLatch countDownLatch, 
                                  File file, byte[] bytes) { 
        this.countDownLatch = countDownLatch; 
        this.file = file; 
        this.bytes = bytes; 
    }

    public Object call() throws Exception { 
        BufferedOutputStream bufferedOutputStream = null; 
        try { 
            bufferedOutputStream 
              = new BufferedOutputStream(new FileOutputStream(file)); 
            bufferedOutputStream.write(bytes); 
        } catch (Exception e) { 
            e.printStackTrace(); 
        } finally { 
            if (bufferedOutputStream != null) { 
                bufferedOutputStream.close(); 
            } 
            countDownLatch.countDown(); 
        } 
        return null; 
    }
}

CountDownLatchのカウントを2で初期化しているので、awaitメソッドはcountDownメソッドが2回実行されるまでスレッドを待機させます。 ファイルの書き込みが完了した時点でcountDownメソッドを実行しているので、2つのファイルの書き込みが完了すると「END」が表示されます。