Java RestTemplate 线程安全吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22989500/
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
Is RestTemplate thread safe?
提问by Raedwald
Is a Spring RestTemplate
thread-safe? That is
SpringRestTemplate
线程安全吗?那是
- Is a
RestTemplate
a Strategy object that multiple connections can safely share. or - Is a
RestTemplate
a connection object (like a data-base connection), which can not be shared while in use, and requires creation afresh, or pooling, for each connection.
- 是一个
RestTemplate
Strategy 对象,多个连接可以安全地共享。或者 - 是一个
RestTemplate
连接对象(如数据库连接),在使用时不能共享,需要为每个连接重新创建或池化。
采纳答案by Raedwald
RestTemplate
is thread safe(emphasis added):
RestTemplate
是线程安全的(强调):
Conceptually, it is very similar to the
JdbcTemplate
,JmsTemplate
, and the various other templates found in the Spring Framework and other portfolio projects. This means, for instance, that theRestTemplate
is thread-safe once constructed
从概念上讲,它是非常相似的
JdbcTemplate
,JmsTemplate
和Spring框架和其他投资项目中发现的各种其他模板。这意味着,例如,一旦构造,它RestTemplate
就是线程安全的
Objects of the RestTemplate
class do not change any of their state information to process HTTP: the class is an instance of the Strategy design pattern, rather than being like a connection object. With no state information, there is no possibility of different threads corrupting or racing state information if they share a RestTemplate
object. This is why it is possible for threads to share these objects.
RestTemplate
类的对象不会改变它们的任何状态信息来处理 HTTP:该类是 Strategy 设计模式的实例,而不是像一个连接对象。没有状态信息,如果它们共享一个RestTemplate
对象,就不会有不同线程损坏或竞争状态信息的可能性。这就是线程可以共享这些对象的原因。
If you examine the source code of RestTemplate
you will see that it does not use synchronized
methods or volatile
fields to provide thread-safety after construction of the object. So it is notsafe to modify a RestTemplate
object after construction. In particular, it is unsafe to add a message converter.
如果您检查源代码,RestTemplate
您将看到它在构造对象后不使用synchronized
方法或volatile
字段来提供线程安全。因此,它是不是安全的修改RestTemplate
施工后的对象。特别是添加消息转换器是不安全的。
To provide it with a list of message converters you must do one of the following:
要为其提供消息转换器列表,您必须执行以下操作之一:
- Use the
RestTemplate(List<HttpMessageConverter<?>> messageConverters)
constructor. As the internal list ofmessageConverters
isfinal
, this safely publishes the list of message converters. - Use the
setMessageConverters(List<HttpMessageConverter<?>> messageConverters)
mutator andthen safely-publishthe changedRestTemplate
object. Using a Spring bean definition that has a<property name="messageConverters"><list>...
does this, as the bean will be safely published by the thread setting up the containerin most practical use cases. - Use
List.add
on the reference returned bygetMessageConverters()
and then safely publish the changedRestTemplate
object. However, the documentation forRestTemplate
does not explicitly state that it returns a reference that can be used to alter the list of message converters. The current implementation does, but possibly the implementation might be changed to return aCollections.unmodifiableList
or a copy of the list. So it might be better not to change it this way.
- 使用
RestTemplate(List<HttpMessageConverter<?>> messageConverters)
构造函数。由于messageConverters
is的内部列表final
,这可以安全地发布消息转换器列表。 - 使用
setMessageConverters(List<HttpMessageConverter<?>> messageConverters)
mutator ,然后安全地发布更改的RestTemplate
对象。使用具有 a 的 Spring bean 定义可以<property name="messageConverters"><list>...
做到这一点,因为在大多数实际用例中,bean将由设置容器的线程安全地发布。 List.add
在由返回的引用上使用getMessageConverters()
,然后安全地发布更改的RestTemplate
对象。但是, 的文档RestTemplate
没有明确声明它返回可用于更改消息转换器列表的引用。当前的实现是这样,但可能会更改实现以返回Collections.unmodifiableList
列表的一个或副本。所以最好不要以这种方式改变它。
Note that the first case is the only means of setting up the message converters when constructing the object, so it iscorrect to say that it "is thread safe once constructed".
需要注意的是第一种情况是构建对象时建立的消息转换器的唯一手段,因此它是正确的说,它“是线程安全的,一旦构成”。
The class is part of the Spring Framework, so in almost all practical cases objects of the class will be set up as part of a Spring Application Context, using the first (dependency injection using a constructor) or second (dependency injection using a setter) methods, and so would be guaranteed to be safely published to multiple threads.
该类是 Spring 框架的一部分,因此在几乎所有实际情况下,该类的对象都将设置为 Spring 应用程序上下文的一部分,使用第一个(使用构造函数的依赖注入)或第二个(使用 setter 的依赖注入)方法,因此可以保证安全地发布到多个线程。
回答by Ross
Hate to disagree with the accepted answer above (emphasis added), but no it is not Thread safe. Even after creation. Internally it is playing around with ArrayLists, I have not dug into the source. I have seen too many of these:
讨厌不同意上面接受的答案(强调已添加),但不,它不是线程安全的。即使在创建之后。在内部,它正在使用 ArrayLists,我还没有深入研究源代码。我见过太多这样的:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at org.springframework.web.client.RestTemplate$AcceptHeaderRequestCallback.doWithRequest(RestTemplate.java:677)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:545)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:253)
回答by Vasilis Nicolaou
It is thread safe from the library's point of view. For instance, the getMessageConverters() is public Which means that if someone gets hold on the list and modifies it outside of the purpose of the library then it will cause issues (and even the setter method, if it's called at any moment after RestTemplate instantiation - and while being used by other threads obviously, boom!). Which probably is what happened to Ross (not enough reputation to reply to the answer, but I'm backing up both the thread-safe and not thread-safe arguments)
从库的角度来看,它是线程安全的。例如,getMessageConverters() 是公共的,这意味着如果有人持有列表并在库的目的之外修改它,那么它会导致问题(甚至是 setter 方法,如果它在 RestTemplate 实例化后的任何时刻被调用- 虽然显然被其他线程使用,但繁荣!)。这可能是发生在罗斯身上的事情(没有足够的声誉来回复答案,但我同时支持线程安全和非线程安全的论点)
回答by Ross
Alright, though I might dig the old code out from source control that caused these issues.
好吧,虽然我可能会从导致这些问题的源代码管理中挖掘出旧代码。
I think it would be fair to say that even synchronizing on creation there exist circumstances where another thread can modify the internal collections. So best be careful. Looking at the old code, yes it was actually using a message converter. But only when synchronized on creation.
我认为可以公平地说,即使在创建时同步,也存在另一个线程可以修改内部集合的情况。所以最好小心点。查看旧代码,是的,它实际上是在使用消息转换器。但只有在创建时同步。
restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingHymanson2HttpMessageConverter());
After that the only interaction with RestTemplate was with this:
之后与 RestTemplate 的唯一交互是这样的:
return restTemplate.postForObject(url, object, clazz);
This is also the line that eventually throws the exception.
这也是最终抛出异常的行。
There is of course no interaction with the message converter (we have no local reference to it).
当然没有与消息转换器的交互(我们没有本地引用它)。
Looking at the stacktrace, and the spring source code, the error occurred at this line:
查看stacktrace和spring源代码,错误发生在这一行:
for (HttpMessageConverter<?> converter : getMessageConverters()) {
So what do we have?
那么我们有什么?
- We have concurrent access to the messageConverters
- If our code didn't do it, then which code did? I don't have an answer. My solution at the time was to create a new RestTemplate every time as performance was not a concern in this app.
- 我们可以同时访问 messageConverters
- 如果我们的代码没有做到,那么哪个代码做到了?我没有答案。我当时的解决方案是每次都创建一个新的 RestTemplate,因为在这个应用程序中性能不是问题。
So in summary, there are circumstances where things may not be thread safe, certainly if you were to play around with message converters directly. This case though is a strange one, but I thought it would be useful to publish it.
所以总而言之,在某些情况下,事情可能不是线程安全的,当然,如果您要直接使用消息转换器。这个案例虽然很奇怪,但我认为发布它会很有用。