RestTemplate线程安全吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RestTemplate线程安全吗?相关的知识,希望对你有一定的参考价值。

Spring RestTemplate线程安全吗?那是

  • RestTemplate是一个策略对象,多个连接可以安全地共享。要么
  • RestTemplate是一个连接对象(如数据库连接),在使用时无法共享,并且需要为每个连接重新创建或汇集。
答案

RestTemplate is thread safe(重点补充):

从概念上讲,它与JdbcTemplateJmsTemplate以及Spring Framework和其他项目组合项目中的各种其他模板非常相似。这意味着,例如,RestTemplate一旦构造就是线程安全的


RestTemplate类的对象不会更改任何状态信息来处理HTTP:类是策略设计模式的实例,而不是像连接对象。没有状态信息,如果共享RestTemplate对象,则不可能有不同的线程破坏或竞争状态信息。这就是线程可以共享这些对象的原因。

如果你检查the source code of RestTemplate,你会发现它在构造对象后不使用synchronized方法或volatile字段来提供线程安全性。因此,在构造之后修改RestTemplate对象是不安全的。特别是,添加消息转换器是不安全的。

要为其提供消息转换器列表,您必须执行以下操作之一:

  • 使用RestTemplate(List<HttpMessageConverter<?>> messageConverters)构造函数。由于messageConverters的内部列表是final,这个safely publishes the list of message converters
  • 使用setMessageConverters(List<HttpMessageConverter<?>> messageConverters) mutator,然后使用safely-publish更改的RestTemplate对象。使用具有<property name="messageConverters"><list>...的Spring bean定义可以做到这一点,就像大多数实际用例中的bean will be safely published by the thread setting up the container一样。
  • List.add返回的引用上使用getMessageConverters(),然后安全地发布更改的RestTemplate对象。但是,RestTemplate的文档没有明确声明它返回一个可用于更改消息转换器列表的引用。当前的实现确实如此,但可能会更改实现以返回Collections.unmodifiableList或列表的副本。所以最好不要这样改变它。

请注意,第一种情况是在构造对象时设置消息转换器的唯一方法,因此说“一旦构造就是线程安全的”是正确的。

该类是Spring Framework的一部分,因此在几乎所有实际情况中,类的对象将被设置为Spring Application Context的一部分,使用第一个(使用构造函数的依赖注入)或第二个(使用setter的依赖注入)方法,因此将保证安全地发布到多个线程。

另一答案

从图书馆的角度来看,它是线程安全的。例如,getMessageConverters()是公共的,这意味着如果有人抓住列表并在库的目的之外修改它,那么它将导致问题(甚至是setter方法,如果在RestTemplate实例化之后的任何时候调用它 - 显然,当被其他线程使用时,繁荣!)。这可能是Ross发生的事情(没有足够的声誉回复答案,但我正在备份线程安全和非线程安全的参数)

另一答案

好吧,虽然我可能会从导致这些问题的源代码控制中挖掘旧代码。

我认为,即使在创建时进行同步,也存在另一个线程可以修改内部集合的情况。所以最好小心点。看看旧代码,是的,它实际上是使用消息转换器。但只有在创作时同步。

restTemplate = new RestTemplate();

restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());

之后,与RestTemplate的唯一交互就是:

return restTemplate.postForObject(url, object, clazz);

这也是最终抛出异常的行。

当然没有与消息转换器的交互(我们没有本地引用它)。

查看堆栈跟踪和spring源代码,此行发生错误:

for (HttpMessageConverter<?> converter : getMessageConverters()) {

那么我们有什么?

  1. 我们可以同时访问messageConverters
  2. 如果我们的代码没有这样做,那么代码做了什么?我没有答案。我当时的解决方案是每次创建一个新的RestTemplate,因为这个应用程序不关心性能。

总而言之,在某些情况下,事情可能不是线程安全的,当然如果您直接使用消息转换器。这种情况虽然很奇怪,但我认为发布它会很有用。

另一答案

讨厌不同意上面接受的答案(强调添加),但不是不是线程安全。即使在创作之后。在内部,它正在玩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)

以上是关于RestTemplate线程安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

resttemplate远程接口调用 传一个map 怎么调用map参数

为啥基于锁的程序不能组成正确的线程安全片段?

markdown 线程安全相关片段

RestTemplate设置每个请求的超时

resttemplate转发占用cpu

这个代码线程安全吗