1

厄介なバグを含む古いJavaコードを修正する必要があります。

ユーザーがログインすると、コードはLDAPサーバーにクエリを実行してアクセス許可を確認します。これには1〜2秒かかります。

その時間枠の間に別のユーザーがログインすると、最初のユーザーのアクセス許可チェックが2番目のユーザーのアクセス許可で続行されるように見えますが、これはもちろん壊滅的なバグです。最初のスレッドのデータが2番目のスレッドによって上書きされているようです。

コード全体に散在する静的変数とメソッドがたくさんあります。それらを静的にする正当な理由があるのか​​、それとも単に動的にすることができるのか、私にはわかりません。

このコードをスレッドセーフにするための戦略、またはこの一般的なクラスの問題に関するチュートリアルをお勧めしますか?

何が起こるかについての詳細は次のとおりです。まず、標準フローの例:

2012-12-11 15:07:14,146 INFO [TP-Processor20] [MyListener] handleLoginEvent Login Event: username=[USER1]
2012-12-11 15:07:14,865 INFO [TP-Processor20] [MyListener] doInHibernate Group Maps Array has 3 maps inside.
2012-12-11 15:07:14,865 INFO [TP-Processor20] [MyListener] doInHibernate External Group NAME=[*] USER=[USER1] is a member? true
...
2012-12-11 15:07:16,036 INFO [TP-Processor20] [MyListener] doInHibernate External Group NAME=[ou:GROUP-A] USER=[USER1] is a member? false
...
2012-12-11 15:07:16,068 INFO [TP-Processor20] [MyListener] doInHibernate External Group NAME=[ou:GROUP-Z] USER=[USER1] is a member? false
TP-Processor20 done.


2012-12-11 15:07:33,099 INFO [TP-Processor9] [MyListener] handleLoginEvent Login Event: username=[USER1]
2012-12-11 15:07:33,677 INFO [TP-Processor9] [MyListener] doInHibernate Group Maps Array has 3 maps inside.
2012-12-11 15:07:33,677 INFO [TP-Processor9] [MyListener] doInHibernate External Group NAME=[*] USER=[USER1] is a member? true
...
2012-12-11 15:07:33,755 INFO [TP-Processor9] [MyListener] doInHibernate External Group NAME=[ou:GROUP-A] USER=[USER1] is a member? false
...
2012-12-11 15:07:33,786 INFO [TP-Processor9] [MyListener] doInHibernate External Group NAME=[ou:GROUP-Z] USER=[USER1] is a member? false
TP-Processor9 done.

これが問題のログの抜粋です。2回目のログイン後、ユーザー名を保持する変数がどのように異なるかに注意してください。

2012-12-11 15:07:53,082 INFO [TP-Processor9] [MyListener] handleLoginEvent Login Event: username=[USER2]
2012-12-11 15:07:53,661 INFO [TP-Processor9] [MyListener] doInHibernate Group Maps Array has 3 maps inside.
2012-12-11 15:07:53,676 INFO [TP-Processor9] [MyListener] doInHibernate External Group NAME=[*] USER=[USER2] is a member? true

note the handleLoginIvent from another user
2012-12-11 15:07:53,676 INFO [TP-Processor1] [MyListener] handleLoginEvent Login Event: username=[USER1]
...
note that the USER= value has changed to that of TP-Processor1. Also, the "is a member" test returns now true which is incorrect for user USER1. It is actually user USER2 who is a member of that group.
2012-12-11 15:07:53,832 INFO [TP-Processor9] [MyListener] doInHibernate External Group NAME=[ou:GROUP-A] USER=[USER1] is a member? true
...
2012-12-11 15:07:53,989 INFO [TP-Processor9] [MyListener] doInHibernate External Group NAME=[ou:GROUP-Z] USER=[USER1] is a member? false
TP-Processor9 done

2012-12-11 15:07:54,286 INFO [TP-Processor1] [MyListener] doInHibernate Group Maps Array has 3 maps inside.
2012-12-11 15:07:54,286 INFO [TP-Processor1] [MyListener] doInHibernate External Group NAME=[*] USER=[USER1] is a member? true
...
2012-12-11 15:07:54,364 INFO [TP-Processor1] [MyListener] doInHibernate External Group NAME=[ou:GROUP-A] USER=[USER1] is a member? false
...
2012-12-11 15:07:54,551 INFO [TP-Processor1] [MyListener] doInHibernate External Group NAME=[ou:GROUP-Z] USER=[USER1] is a member? false
4

1 に答える 1

3

すべての静的変数またはインスタンス変数を削除し、代わりにメソッドからメソッドに引数として渡されるローカル変数に置き換えてみてください。したがって、コードはステートレスになり、スレッドセーフになります。たとえば、次のように置き換えます

private static int foo;

public void bar() {
    ...
    foo = someMethod();
    ...
    baz();
}

private void baz() {
   ...
   someOtherMethod(foo);
   ...
}

public void bar() {
    ...
    int foo = someMethod();
    ...
    baz(foo);
}

private void baz(int foo) {
   ...
   someOtherMethod(foo);
   ...
}

もう1つの、おそらくより良いオプションは、最初からやり直すことです。多くの静的変数を使用するマルチスレッドコードは保存する価値がない可能性があり、おそらく他の多くのバグや悪い習慣が含まれているためです。

于 2012-12-14T13:03:00.973 に答える