我正在创建一个Web应用程序并遇到线程安全问题。在阅读了几个类似的问题之后,我仍然对我的案子感到困惑。我正在使用java spring框架来设置REST Web服务。所有请求(Person对象的JSON)都将传递给checkIfGoodName
函数,如Checker.checkIfGoodName(person)
。它们都是静态方法调用。我想知道,这个函数是Checker.checkIfGoodName
线程安全吗?如果没有,如何修改代码?我的代码如下:
Checker.java
public class Checker {
public static void checkIfGoodName(Person person){
checkingName(Person person);
}
private static void checkingName(Person person){
if(person.getName()==null){
PersonUtils.addErrorMessage(Person person, new String("Name is empty"));
}
}
}
PersonUtils.java
public class PersonUtils {
public static void addErrorMessage(Person person, String errorMessage){
List<Message> msg = person.getMessageList();
if(msg!=null){
msg.add(buildMessage(errorMessage));
}
}
public static void buildMessage(String errorMessage){
if(errorMessage != null){
Message msg = new Message();
msg.setMsg(errorMessage);
}
}
}
答案 0 :(得分:7)
不要考虑使方法线程安全。线程安全是关于保护数据的完整性。更具体地说,它是在某些其他线程正在更改数据的过程中阻止线程访问数据。
您的PersonUtils.addErrorMessage(person, message)
方法会修改属于List
个实例的Person
个实例。访问列表应该是synchronized
如果相同的列表可以被两个不同的线程修改,或者它可以被一个线程修改并被其他线程访问。
将项添加到列表需要几个步骤,如果线程A能够在线程B执行了某些步骤但不是所有步骤的某个时刻看到它,则该列表几乎肯定会处于非法状态。如果两个线程同时尝试修改列表,那就更糟了:这可能会使列表处于永久的非法状态。
即使在同一个Person实例上运行的线程实际上并不同时执行,仍然仍然需要同步。原因是,如果没有同步,计算机硬件和操作系统不保证一个线程在内存中进行的更改将立即对其他线程可见。但是,synchronized
来救你:
在线程B进入synchronized(foo)
块之后,线程A在离开synchronized(foo)
块之前所做的更改将显示给线程B.
最简单的事情是,如果不同的线程访问同一个Person实例,那就是在addErrorMessage(...)方法中对Person对象进行同步:
public static void addErrorMessage(Person person, String errorMessage){
synchronized(person) {
List<Message> msg = person.getMessageList();
if(msg!=null){
msg.add(buildMessage(errorMessage));
}
}
}
答案 1 :(得分:2)
我没有看到PersonUtils
有状态,但是可能是同一个Person
实例同时传递两次以便更好地锁定Person
实例的情况,
假设您实际上有与实例关联的消息列表而不是static
属性
将错误消息与Model
本身关联也不好,尝试使用您提到的框架探索一些标准做法