独習Java第9章 マルチスレッドプログラミング(9.3)
昨日の9.1, 9.2に続いてスレッドの同期の部分。
環境:MacOS 10.6.5 / Oracle(Sun) JDK6 update22
スレッドの同期
スレッドを同期させるには2つ方法がある。
- synchronized修飾子を指定してメソッドを同期させる
- synchronizedブロックを使う
後者は存在すら知らなかった……
Javaのクラスライブラリのほとんどはスレッドセーフに作られているが、StringBuilderはスレッドセーフではないのでStringBufferを使う必要がある。
書いてみる
// Main.java class Sync { synchronized void add(int i) { this._value += i; } int getValue() { return this._value; } private int _value = 0; } class ThreadEx extends Thread { ThreadEx(Sync sync) { this._sync = sync; } public void run() { try { for (int i = 1; i <= 1000000; i++) { this._sync.add(20); } } catch (Exception e) { e.printStackTrace(); } } private Sync _sync; } class Main { public static void main(String args[]) { Sync sync = new Sync(); Thread t[] = new ThreadEx[THREAD_COUNT]; for (int i = 0; i < THREAD_COUNT; i++) { t[i] = new ThreadEx(sync); t[i].start(); } for (int i = 0; i < THREAD_COUNT; i++) { try { t[i].join(); } catch (Exception e) { e.printStackTrace(); } } System.out.println(sync.getValue()); } private static final int THREAD_COUNT = 100; }
実行してみる
$ javac Main.java
$ java Main
2000000000
ちゃんと動いた!
書いてみる(その2)
今度はsynchronized修飾子でなく、synchronizedブロックで書いてみる。
4c4 < void add(int i) --- > synchronized void add(int i) 6,9c6 < synchronized (this) < { < this._value += i; < } --- > this._value += i;
実行してみる(その2)
$ javac Main.java
$ java Main
2000000000
synchronizedを書かないで実行してみる
6c6,9 < this._value += i; --- > synchronized (this) > { > this._value += i; > }
$ javac Main.java $ java Main 1965696700 $ java Main 1956836400 $ java Main 1949922900
前者2つより明らかに速いのだけれど、値が不定に。
おまけ
$ javac -J-Dfile.encoding=UTF-8 Main.java $ java -Dfile.encoding=UTF-8 Main
で実行するとメッセージが化けないみたい。
今日はここまで。次はデッドロック。できればスレッド間の通信も終わらせたいなー。