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 的线程安全就不是问题,也不会影响您的测试结果。
下面是一个示例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
的共享实例上完成 - JVM 上下文切换到线程 2 并在
outputResponse
的同一实例上完成setSomeValue(...)
。outputResponse
现在包含线程 1 和 2 的状态 - JVM 上下文切换回线程 1,然后线程 1 基于此混合状态对象创建
OutputResponseEntity
。
setSomeOtherValue(...)
如果您将 outputResponse
设置为 execute
方法的局部变量并传递它,它实际上变成了线程局部内存,因此每个线程都有一个单独的对象实例。这可能就是您想要的;如果您不需要在线程之间共享信息,只需将其设为本地变量即可。如果您确实确实需要在线程之间协调 sets/gets(在这个简单示例中似乎并非如此),那么您将需要进行某种同步 and/or 设计程序流程更好(取决于您的需要)。
这个 class 在设计上不是线程安全的。但它显然被用作某些框架中的组件。不可能,这个框架确保你的 ExampleProvider
的任何实例都不会在线程之间共享。如果是这样,那么 class 的线程安全就不是问题,也不会影响您的测试结果。