2

編集:シングルトンのコンストラクターが複数回呼び出されていることがわかったので、クラスが別々のクラスローダーによって複数回ロードされているようです。Tomcatでグローバルシングルトンを作成するにはどうすればよいですか?私はグーグルしてきましたが、今のところ運がありません。

このように構築したシングルトンオブジェクトがあります。

private static volatile KeyMapper mapper = null;

public static KeyMapper getMapper()
{
    if(mapper == null)
    {
        synchronized(Utils.class)
        {
            if(mapper == null)
            {
                mapper = new LocalMemoryMapper();
            }
        }
    }

    return mapper;
}

KeyMapperクラスは、基本的にHashMapの同期ラッパーであり、1つはマッピングを追加し、もう1つはマッピングを削除する2つの関数のみを備えています。32ビットWindowsマシンのTomcat6.24で実行すると、すべてが正常に機能します。ただし、64ビットLinuxマシン(OpenJDK1.6.0-b09を搭載したCentOS5.4)で実行している場合、マッピングを1つ追加し、KeyMapperが追加されたことを確認するために使用するHashMapのサイズを出力します(つまり、サイズ= 1を確認します)。次に、別のリクエストでマッピングを取得しようとしましたが、nullを取得し続け、HashMapのサイズを確認したところ0でした。削除するすべての呼び出しをコメントアウトしたので、マッピングが誤って削除されていないことを確信しています。 (そして、クリアや他のミューテーターは使用しません。取得して配置するだけです)。

リクエストはTomcat6.24(200スレッドと最低4スレッドを使用するように構成されています)を経由し、クラスが誤ってガベージコレクションを取得しないように-Xnoclassgcをjvmに渡しました(jvmも-serverモードで実行されています)。また、ガベージコレクションが行われていないことを確認するために、ガベージコレクションが発生した場合にstderrに出力するfinalizeメソッドをKeyMapperに追加しました。

私は気が遠くなり、HashMapのエントリが1分間あり、次のエントリがない理由がわかりません:(

4

5 に答える 5

5

もう1つの大げさな推測:2つのリクエストがWebアプリの異なるコピーによって処理されている可能性はありますか?それぞれが独自のClassLoaderものであるため、シングルトンの異なるコピーがあります。

于 2010-05-03T12:36:21.017 に答える
1

このソリューションを使用すると、JVMは、マッパーが1つだけであり、使用前に初期化されることを保証します。

public enum KeyMapperFactory {

    ;

    private static KeyMapper mapper = new LocalMemoryMapper();  

    public static KeyMapper getMapper() {
        return mapper;
    }
}
于 2010-05-03T11:32:12.990 に答える
1

外側のチェックを外してみましたか

if(mapper == null)
{

これにより、常に同期ポイントに到達します。これは微妙な問題ですが、ダブルチェックされたロックイディオムの問題に遭遇している可能性があります。ここや他の多くの記事で説明されています。

問題が実際に誰かを噛むのを見たことがないことを認めなければなりませんが、これは確かにそのように聞こえます。

于 2010-05-03T09:14:29.277 に答える
1

これは問題の原因ではない可能性がありますが、誤ったダブルチェックロックを使用しています。これを見て、

http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java

于 2010-05-03T12:10:33.513 に答える
0

私はかなり貧弱な修正を見つけました。コードをJARとしてエクスポートし、$ TOMCAT / libに配置すると、機能しました。これは明らかにクラスローダーの問題です。

編集:解決策を見つけました

さて、私はついに問題を理解しました。

server.xmlにを追加し、パスを「」に設定することで、アプリケーションをサーバーのデフォルトアプリケーションにしました。ただし、何かの場合はURL http://localhost/somepage.jspを介しアクセスしていましたが、その他の場合はURLhttp://localhost/appname/anotherpage.jspを介してアクセスしていました。

http:// localhost / appnameの代わりにhttp:// localhost /を使用するようにすべてのURLを変更すると、問題が修正されました。

于 2010-05-03T19:48:02.593 に答える