java 中的实例变量和线程安全

Instance variable and thread safety in java

下面是一个示例class(从我正在测试的那个修改而来),​​我想知道这是否是线程安全的class。

我看到其他帖子和博客回答说实例变量不一定是线程安全的。 (显示的大多数示例使用原始类型)

当我在方法外部创建 OutputResponse 对象并从 soapui 对其进行负载测试时,它失败了,但是当我在方法内部创建对象时,负载测试总是成功的。

@Service
public class ExampleProvider {

    private OutputResponse outputResponse;

        @Post
        @Path("/test")
        @Consumes("application/json")
    @Produces("application/json")
        public OutputResponseEntity execute (InputRequest inputRequest) {

        outputResponse = new OutputResponse();
            outputResponse.setSomeValue("this is test");
            populateOutputResponse();
        }

        private OutoutResponseEntity<OutputResponse> populateOutputResponse () {
            if(null != inputRequest) {
                outputResponse.setSomeOtherValue(inputRequest.getName());
            }
            return new OutputResponseEntity(outputResponse,httpstatus.OK);
        }
}

您发布的代码在语法上似乎不太正确 -- 您的意思是:

public OutputResponseEntity execute (InputRequest inputRequest) {
    outputResponse = new OutputResponse();
    outputResponse.setSomeValue("this is test");
    return populateOutputResponse(inputRequest);
}

假设这就是您的意思,那么似乎多个线程正在使用 ExampleProvider 的同一个实例。这可以解释为什么将 outputResponse 设置为 execute 本地(然后您可能也想将其传递给 populateOutputResponse)修复您的测试。

如果多个线程正在使用 ExampleProvider 的同一个实例,那么,就像您现在的代码一样,outputResponse 也在这些线程之间共享,并且没有进行同步以防止竞争条件.所以,可能会发生这样的事情:

  • 线程 1 在 outputResponse
  • 的共享实例上完成 setSomeOtherValue(...)
  • JVM 上下文切换到线程 2 并在 outputResponse 的同一实例上完成 setSomeValue(...)outputResponse 现在包含线程 1 和 2 的状态
  • JVM 上下文切换回线程 1,然后线程 1 基于此混合状态对象创建 OutputResponseEntity

如果您将 outputResponse 设置为 execute 方法的局部变量并传递它,它实际上变成了线程局部内存,因此每个线程都有一个单独的对象实例。这可能就是您想要的;如果您不需要在线程之间共享信息,只需将其设为本地变量即可。如果您确实确实需要在线程之间协调 sets/gets(在这个简单示例中似乎并非如此),那么您将需要进行某种同步 and/or 设计程序流程更好(取决于您的需要)。

这个 class 在设计上不是线程安全的。但它显然被用作某些框架中的组件。不可能,这个框架确保你的 ExampleProvider 的任何实例都不会在线程之间共享。如果是这样,那么 class 的线程安全就不是问题,也不会影响您的测试结果。