CountDownLatchを使ってスレッド処理の完了を待つ

とあるプロジェクトで`CountDownLatch`が頻繁に出てきた。
こいつは一体何をしてくれる子なんだ？ってことで調べてみた。

以下にスレッド処理を行うサンプルコードを示しながら説明していく。
各スレッドが「wait...」を標準出力し、全スレッドの処理が完了したら「finish!」を出力したい、そんなサンプルコードである。

### CountDownLatch未使用の場合
---
```java:【1】CountDownLatchを使っていないサンプルコード
public class MyClass {
	private static final int LOOP_COUNT= 10;

	public static void main(String[] args) throws Exception {
		for (int i = 0; i < LOOP_COUNT; i++) {
			new Thread() {
				public void run() {
					System.out.println("wait...");
				}
			}.start();
		}
		System.out.println("finish!");
	}
}
```

```text:【1】の実行結果
wait...
wait...
wait...
wait...
wait...
wait...
wait...
wait...
finish!
wait...
wait...
```
######※ 実行のタイミングで上に示した結果と異なる場合があります。

おやおや。。。
まだ終わってないのに「finish!」って出てしまったよｗ

というわけで本日の主役`CountDownLatch`を使ってみましょう。

### CountDownLatchを使用した場合
---
```java:【2】CountDownLatchを使用したサンプルコード
public class MyClass {
	private static final int LOOP_COUNT= 10;
	private static CountDownLatch countDownLatch = new CountDownLatch(LOOP_COUNT);

	public static void main(String[] args) throws Exception {
		for (int i = 0; i < LOOP_COUNT; i++) {
			new Thread() {
				public void run() {
					System.out.println("wait...");
					countDownLatch.countDown();
				}
			}.start();
		}
		countDownLatch.await();
		System.out.println("finish!");
	}
}
```
```text:【2】の実行結果
wait...
wait...
wait...
wait...
wait...
wait...
wait...
wait...
wait...
wait...
finish!
```
######※上記は何度実行しても同じ結果になります

「finish!」って正しいタイミングで言うようになったｗ

###サンプルコード【1】と【2】の違い
---
【2】のサンプルコードには以下の3行が加わっている。

1.総スレッド数分で`CountDownLatch`を生成

```java
private static CountDownLatch countDownLatch = new CountDownLatch(LOOP_COUNT);
```
2.`countDownLatch `をカウントダウン
初期が`LOOP_COUNT`(=10)なので、このメソッドが呼ばれる毎に9,8,7...とカウントダウンされていく。

```java
countDownLatch.countDown();
```
3.全スレッドの処理が完了するのを待つ
具体的には`countDownLatch `が0になるまで待機する。

```java
countDownLatch.await();
```

###まとめ
---
スレッド処理でファイル書き込みをしていたり、何かしら処理は分散させて早くしたいけど、次の処理に進むのは全部終わってからじゃないとダメなの！って時にとても有効ですね。
やたら頻繁に目にした理由がわかりました。

次は`ExecutorService`,`Semaphore`辺りを調べたいなと思います。

###参考サイト
---
* http://otn.oracle.co.jp/technology/global/jp/sdn/java/private/techtips/2005/tt0216.html
* http://d.hatena.ne.jp/nowokay/20081127/1227748012

###~~(本っ当に心底どうでもいい)~~おまけ
---
参考サイト([※1](http://d.hatena.ne.jp/nowokay/20081127/1227748012))のサンプルコードをちょっといじって顔文字が流れるようにしてみたら勉強が捗りましたｗ

```java:しゃきーん君が流れちゃうサンプルコード
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

import javax.swing.JFrame;
import javax.swing.JTextField;

import lombok.AllArgsConstructor;

public class SemaphoreSample {

	private static final int THREAD_COUNT = 10;
	private static final int ACTIVE_COUNT = 3;
	private static Semaphore semaphoe = new Semaphore(ACTIVE_COUNT);
	private static CountDownLatch countDown = new CountDownLatch(THREAD_COUNT);

	public static void main(String args[]) throws Exception {
		JFrame f = new JFrame("Sample");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setLayout(new GridLayout(0, 1));

		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		f.setBounds((screenSize.width - 400) / 2,
				(screenSize.height - 300) / 2, 400, 300);

		ExecutorService ex = Executors.newFixedThreadPool(THREAD_COUNT);
		for (int i = 0; i < THREAD_COUNT; ++i) {
			JTextField tf = new JTextField();
			f.add(tf);

			Runner r = new Runner(tf);
			ex.submit(r);
		}
		f.setVisible(true);
		countDown.await();
		System.out.println("finish!");

	}

	@AllArgsConstructor
	private static class Runner implements Runnable {
		private JTextField tf;

		@Override
		public void run() {
			try {
				String tr = "(＾・ ω ・＾)";
				for (int j = 0; j < 50; ++j) {
					tf.setText(tr);
					tr = " " + tr;
					Thread.sleep(50);
				}
				semaphoe.acquire();
				for (int i = 0; i < 50; ++i) {
					tf.setText(tr);
					tr = " " + tr;
					Thread.sleep(50);
				}
			} catch (Exception ex) {
			} finally {
				semaphoe.release();
				countDown.countDown();
			}
		}
	}
}
```
どうなったかは実行してみてねｗ