Javaマルチスレッド学習ノート(一)-Javaの非スレッドセキュリティ問題


最近、Javaマルチスレッドの勉強を始め、本を読みながらメモを取り、自分の理解を少し書きます.まず、Javaの非スレッドセキュリティの問題を投げ出します.非スレッドセキュリティの問題は、主に、複数のスレッドが同じオブジェクトの同じインスタンス変数を操作すると、値が変更され、値が同期しない場合があり、プログラムの実行プロセスに影響します.次のコードは、スレッド以外のセキュリティの簡単な例です.
public class LoginServletTest
{
    public static void main(String args[])
    {
        ALogin a = new ALogin();
        BLogin b = new BLogin();
        b.start();
        a.start();
    }
}

class LoginServlet
{
    private static String usernameRef;
    private static String passwordRef;

    synchronized public static void doPost(String username, String password)
    {
        try
        {
            usernameRef = username;
            if(username.equals("a"))
            {
                Thread.sleep(5000);
            }
            passwordRef = password;
            System.out.println("username=" + usernameRef + " password=" + password);

        }
        catch(InterruptedException e)
        {
            e.printStackTrace();
        }
    }
}

class ALogin extends Thread
{
    @Override
    public void run()
    {
        LoginServlet.doPost("a", "aa");
    }
}

class BLogin extends Thread
{
    @Override
    public void run()
    {
        LoginServlet.doPost("b", "bb");
    }
}

実行結果は次のとおりです.
username=b password=bb
username=b password=aa

この結果が出た理由を分析します.
  • まず、mainメソッドで作成されたスレッドaが起動するとrunメソッドが実行され、runメソッドではLoginServiceクラスの静的メソッドdoPostが呼び出される.このときdoPostメソッドのusernameパラメータは「a」であるため、aスレッドはLoginServiceクラスのusernameRef静的変数値をaに変更すると5秒休止する.
  • メインスレッドmainはa.start()を実行した後に実行を継続し、bスレッドを作成した.bスレッド実行時runメソッドは同様にdoPostメソッドを呼び出した.doPostメソッドのusernameパラメータは「a」ではないため、bスレッドはLoginServiceクラスの静的変数usernameRef値をbに変更した後にpasswordRefの値をbbに変更し続け、passwordRefの値をbbに変更する.その後、bスレッドは結果を印刷して実行を終了する.
  • aスレッドは5秒間休眠して目が覚めた後、Thread.sleep(5000);の次の文は実行を続けるので、aスレッドはpasswordRefの値をaaに変更しますが、aスレッドはusernameRefの値を変更していません.このときusernameRefの値はbスレッドによってbに変更されているので、最後にaスレッドが印刷した結果は上記のようになります.この例はJava非スレッドセキュリティの中で最も簡単な例で、Javaマルチスレッドは複雑な問題で、必要絶えず深く勉強する.