Categories: Java

【Java】スレッドセーフな書き方を目指す(メモ)

  • ステートレスにする(クラス変数・インスタンス変数を使わずにローカル変数を用いる。)
  • メソッドに変数を渡したい場合は、その都度渡す。
  • 定数等、static宣言するものはクラス変数やインスタンス変数でも可。
  • 文字の連結にはStringBufferを使用する。(StringBuilderは使わない。)
  • 日付を操作する場合はLocalDateTimeクラスを使用する。(DataクラスやCalendarクラスを使わない。)
  • SimpleDateFormatクラスの代わりにDateTimeFormatterクラスを使用する。(前者はスレッドセーフではないが、後者は不変クラスかつ、スレッドセーフである。)
  • 同期化する必要がある処理にはsynchronizedを付与することを検討する。
  • 読み書きするArrayListを用いる場合はCopyOnwriteArrayListクラスを用いる
  • 読み取り専用のArrayListを用いる場合はUnmodifiableListクラスを用いる
  • ローカル変数の値はメモリ上スタック領域に保持されるため、1つのスレッドからしか参照されない。
  • 一方、クラス変数・インスタンス変数はヒープ領域に保持されるため、複数のスレッドから参照されてしまう。
  • SimpleDateFormatは使わない。代わりにDateTimeFormatterを使う。

synchronized

synchronizedメソッドの基本的な使い方は以下のとおりです。

synchronizedブロック

private int method1(int x) {
    //複数のスレッドで使用する可能性のある部分はsynchronizedを付与する
    synchronized(this){
        return x = x + x;
    }
}

synchronizedメソッド

//複数のスレッドで使用する可能性のある部分はsynchronizedを付与する
synchronized private int method1(int x) {

    return x = x + x;
}

unmodifiableMap

unmodifiableMapメソッドを用いることにより、要素の追加等を防ぐことが出来ます。
以下の例では、要素を追加したタイミングで実行時エラーになっています。

unmodifiableMapメソッド

public class aaa {

    public static final Map<String, String> MAP;
    static {
        Map<String, String> office = new HashMap<>();
        office.put("xlsx", "Excel");
        office.put("docx", "Word");

        MAP = Collections.unmodifiableMap(office);
    }
    public static void main(String[] args) {

        //MAPの要素を出力する。
        System.out.println(MAP.get("xlsx"));

        //MAPに要素を追加する。
        MAP.put("js", "JavaScript");
        //追加した要素を出力。
        System.out.println(MAP.get("js"));
    }

}

実行結果

Excel
Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.Collections$UnmodifiableMap.put(Collections.java:1457)
    at aaa.aaa.main(aaa.java:17)

もしunmodifiableMapを使用しなかった場合は、以下のように要素を追加できてしまいます。

unmodifiableMapメソッド

public class aaa {

    public static final Map<String, String> MAP;
    static {
        Map<String, String> office = new HashMap<>();
        office.put("xlsx", "Excel");
        office.put("docx", "Word");

        MAP = office;;
    }
    public static void main(String[] args) {

        //MAPの要素を出力する。
        System.out.println(MAP.get("xlsx"));

        //MAPに要素を追加する。
        MAP.put("js", "JavaScript");
        //追加した要素を出力。
        System.out.println(MAP.get("js"));
    }

}

実行結果

Excel
JavaScript

unmodifiableList

unmodifiableListメソッドを用いることにより、要素の追加等を防ぐことが出来ます。
以下の例では、要素を追加したタイミングで実行時エラーになっています。

unmodifiableListメソッド

package aaa;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class aaa {

    public static final List<String> CONST_LIST;
    static {
        List<String>  list = new ArrayList<String>();
        list.add("xlsx");
        list.add("docx");

        CONST_LIST = Collections.unmodifiableList(list);
    }
    public static void main(String[] args) {

        //listの要素を出力する。
        System.out.println(CONST_LIST.get(0));

        //listに要素を追加する。
        CONST_LIST.add("js");
        //追加した要素を出力。
        System.out.println(CONST_LIST.get(0));
    }

}

実行結果

xlsx
Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.Collections$UnmodifiableCollection.add(Collections.java:1055)
    at aaa.aaa.main(aaa.java:23)

もしunmodifiableListを使用しなかった場合は、以下のように要素を追加できてしまいます。

unmodifiableListメソッド

public class aaa {

    public static final List<String> CONST_LIST;
    static {
        List<String>  list = new ArrayList<String>();
        list.add("xlsx");
        list.add("docx");

        CONST_LIST = list;
    }
    public static void main(String[] args) {

        //listの要素を出力する。
        System.out.println(CONST_LIST.get(0));

        //listに要素を追加する。
        CONST_LIST.add("js");
        //追加した要素を出力。
        System.out.println(CONST_LIST.get(2));
    }

}

実行結果

xlsx
js

以上で記事の解説はお終い!

もっとJavaやSpringを勉強したい方にはUdemyがオススメ!同僚に差をつけよう!

shiakisudev