java 如何使JAVA中的静态方法线程安全?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27496864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 11:53:19  来源:igfitidea点击:

How to make the static method thread safe in JAVA?

javamultithreadingthread-safetystatic-methods

提问by Terry

I am creating a web application and meet a thread safe problem. After reading several similar questions, I am still confusing about my case. I am using the java spring framework to setup the REST web service. All the request (JSON of Person Object) will be pass to the checkIfGoodNamefunction, like Checker.checkIfGoodName(person). They are all static method call. I am wondering that, is this function, Checker.checkIfGoodNameTHREAD SAFE ? If no, how to modify the code ? I have code as below:

我正在创建一个 Web 应用程序并遇到线程安全问题。看了几个类似的问题,我还是对我的情况感到困惑。我正在使用 java spring 框架来设置 REST web 服务。所有请求(Person 对象的 JSON)都将传递给checkIfGoodName函数,例如Checker.checkIfGoodName(person). 它们都是静态方法调用。我想知道,这个功能是Checker.checkIfGoodName线程安全的吗?如果没有,如何修改代码?我有如下代码:

Checker.java

检查器.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

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

}

回答by Solomon Slow

Don't think about making methodsthread safe. Thread safety is about protecting the integrity of data. More specifically, it is about preventing threads from accessing data when some other thread is in the process of changing the data.

不要考虑使方法线程安全。线程安全是关于保护数据的完整性。更具体地说,它是关于防止线程在其他线程正在更改数据的过程中访问数据。

Your PersonUtils.addErrorMessage(person, message)method modifies Listinstances belonging to Personinstances. Access to the lists should be synchronizedIf the same list can be modified by two different threads, or if it can be modified by one thread and accessed by other threads.

您的PersonUtils.addErrorMessage(person, message)方法修改List属于Person实例的实例。访问列表应该是synchronized如果同一个列表可以被两个不同的线程修改,或者如果它可以被一个线程修改并被其他线程访问。

Adding an item to a list takes several steps, and the list almost certainly will appear to be in an illegal state if thread A is able to see it at a point when thread B has performed some, but not all of the steps. It's worse if two threads attempt to modify the list at the same time: That could leave the list in a permanent, illegal state.

将项目添加到列表需要几个步骤,如果线程 A 能够在线程 B 执行了一些但不是所有步骤的时候看到它,那么列表几乎肯定会出现在非法状态。如果两个线程试图同时修改列表,情况会更糟:这可能会使列表处于永久的非法状态。

You would stillneed synchronization even if threads that operate on the same Person instance don't actually do it at the same time. The reason is, without synchronization, the computer hardware and the operating system do not guarantee that changes made in memory by one thread will immediately be visible to other threads. But, synchronizedcomes to your rescue:

即使在同一个 Person 实例上操作的线程实际上没有同时进行,您仍然需要同步。原因是,如果没有同步,计算机硬件和操作系统不能保证一个线程在内存中所做的更改会立即对其他线程可见。但是,synchronized来拯救你:

Whatever changes thread A makes before it leaves a synchronized(foo)block willbe visible to thread B after thread B enters a synchronized(foo)block.

线程 A 在离开synchronized(foo)块之前所做的任何更改将在线程 B 进入synchronized(foo)块后对线程 B 可见。

The simplest thing for you to do, again ifdifferent threads access the same Person instance, would be to synchronize on the Person object in your addErrorMessage(...) method:

如果不同的线程访问同一个 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));
          }
      }
  }

回答by Jigar Joshi

I don't see PersonUtilshas a state, however it could be the case where you have same Personinstance being passed twice simultaneously so better to make a lock on Personinstance,

我没有看到PersonUtils有状态,但是可能是这样的情况,即您同时Person传递了同一实例两次,因此最好锁定Person实例,

assuming you actually have message list associated with instance and not a staticproperty

假设您实际上有与实例关联的消息列表而不是static属性

also it is not good to associate error message with Modelitself, try exploring some standard practices with the framework you mentioned

将错误消息与Model自身相关联也不好,请尝试使用您提到的框架探索一些标准实践