1

我必须修复一些包含令人讨厌的错误的旧 Java 代码:

当用户登录时,代码通过查询 LDAP 服务器来检查他的权限,这需要一两秒钟。

当另一个用户在该时间范围内登录时,似乎第一个用户的权限检查继续使用第二个用户的权限,这当然是一个灾难性的错误。似乎第一个线程中的数据被第二个线程覆盖。

有很多静态变量和方法散布在整个代码中。我不知道是否有充分的理由让它们成为静态的,或者我是否可以让它们成为动态的。

你能推荐一个如何使这个代码线程安全的策略,或者一个关于这类问题的教程吗?

以下是有关发生情况的一些详细信息。先来个标准流程的例子:

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.

这是问题的日志摘录。请注意第二次登录后保存用户名的变量有何不同。

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);
   ...
}

另一个也许更好的选择是从头开始。因为使用大量静态变量的多线程代码可能不值得保留,并且可能包含许多其他错误或不良做法。

于 2012-12-14T13:03:00.973 回答