他の人が書いていたら読めるけれども、知らなきゃ書けない定型文をあつめたコード型ログを作っている。今回は2回目。
前回: コード型ログ(1) スレッドを止めるにはinterruptを使う - 超ウィザード級ハッカーのたのしみ
いい設計とは言えないかもしれないが、staticな変数の排他を取りたい時がある。この場合には、synchronized(*.class) { }
を使用する。Classオブジェクトは基本的にはstaticでユニークな、つまりシングルトンなオブジェクトである。*1
package org.example.katalog; public class SynchronizedClass { static int count = 0; public void run() { Thread[] ts = new Thread[5]; for (int i = 0; i < ts.length; i++) { // count変数の値をプリントして、カウントアップすることを10回繰り返す。 Thread t = new Thread() { @Override public void run() { for (int j = 0; j < 10; j++) { // SynchronizedClass クラスのロックを取る。 synchronized (SynchronizedClass.class) { System.out.println(count); count++; } } } }; t.start(); ts[i] = t; } for (Thread t : ts) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { new SynchronizedClass().run(); } }
悪い例は、ロック用のオブジェクトを作ることである。
public class SynchronizedClassBad { // ロックオブジェクト private static final Object LOCK_OBJ = new Object(); static int count = 0; public void run() { Thread[] ts = new Thread[5]; for (int i = 0; i < ts.length; i++) { // count変数の値をプリントして、カウントアップすることを10回繰り返す。 Thread t = new Thread() { @Override public void run() { for (int j = 0; j < 10; j++) { // SynchronizedClass クラスのロックを取る。 synchronized (LOCK_OBJ) { System.out.println(count); count++; } // 以下略
なお、staticメソッドにsynchronizedをつけたもの
synchronized static void method() { // 処理 }
は
static void method() { synchronized (this.getClass()) { // 処理 } }
と等価である。
*1:ClassLoaderでややこしいことをしたら別。