如何在多线程环境中有效地使用RestTemplate?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在多线程环境中有效地使用RestTemplate?相关的知识,希望对你有一定的参考价值。

我正在开发一个项目,我需要对运行Restful Service的服务器进行HTTP URL调用,该服务器将响应作为JSON字符串返回。

下面是我使用futurecallables的主要代码 -

public class TimeoutThreadExample {

    private ExecutorService executor = Executors.newFixedThreadPool(10);

    public String getData() {
        Future<String> future = executor.submit(new Task());
        String response = null;

        try {
            response = future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return response;
    }
}

下面是我的Task类,它实现了Callable接口并使用RestTemplate ...

class Task implements Callable<String> {

    private RestTemplate restTemplate = new RestTemplate();

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}

现在我在另一个类DemoTest下面的代码,它在getDataTimeoutThreadExample顺序调用5000 times方法 -

public class DemoTest { 
   public static void main(String[] args) {

        TimeoutThreadExample bc = new TimeoutThreadExample();

        for (int i = 0; i <= 5000; i++) {
        //  TimerTest timer = TimerTest.getInstance(); // line 1
            bc.getData();
        //  timer.getDuration(); // line 2
        }
    }
}       

所以我的问题是RestTemplate应该在我的Task class静态,好像我正确看到它,我正在为RestTemplate中的每个请求重新创建整个连接池,这不是正确的方式我猜...

注意:如果我将RestTemplate静态化,那么在评估测量性能的RestTemplate类中的line1和line2之后,与非静态DemoTest相比,我看到端到端的性能更好。

一般来说,在多线程环境中使用RestTemplate的正确方法是什么?目前我按顺序调用getData方法5000次,但有些客户会以多线程方式调用它,因此需要知道在多线程环境中使用RestTemplate的最佳方法是什么。

可能是在RestTemplate构造函数中使用ConnectionFactory?有什么想法吗?

更新: -

public class TimeoutThreadExample {

    private ExecutorService executor = Executors.newFixedThreadPool(10);
    private RestTemplate restTemplate = new RestTemplate();

    public String getData() {
        Future<String> future = executor.submit(new Task(restTemplate));
        String response = null;

        try {
            response = future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        return response;
    }
}

在我的TaskClass下面 -

class Task implements Callable<String> {

    private RestTemplate restTemplate;

    public Task(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}
答案

如果我不明白你的问题,请纠正我。它看起来非常类似于前一个here

在那里,我们确定RestTemplate是线程安全的。因此没有理由不在任何有意义的地方分享它,即。无论你以何种方式使用它。你的例子似乎是完美的地方。

正如您所说,为每个RestTemplate实例重新创建Task的新实例是浪费。

我会在RestTemplate中创建TimeoutThreadExample并将其作为构造函数参数传递给Task

class Task implements Callable<String> {

    private RestTemplate restTemplate;

    public Task(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public String call() throws Exception {

        String url = "some_url";
        String response = restTemplate.getForObject(url, String.class);

        return response;
    }
}

这样你就可以在所有RestTemplate对象之间共享Task实例。

请注意,RestTemplate使用SimpleClientHttpRequestFactory来创建它的连接。

另一答案

我在春天有这样的多线程安全单件REST模板:

<bean class="org.apache.commons.httpclient.params.HttpConnectionManagerParams" id="httpConnectionManagerParams">
    <property name="connectionTimeout" value="10000"/>
</bean>
<bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager" id="httpConnectionManager">
    <property name="params" ref="httpConnectionManagerParams"/>
</bean>
<bean class="org.apache.commons.httpclient.params.HttpClientParams" id="httpClientParams">
    <property name="authenticationPreemptive" value="true"/>
    <property name="soTimeout" value="10000"/>
</bean>
<bean class="org.apache.commons.httpclient.HttpClient" id="httpClient">
    <constructor-arg ref="httpClientParams"/>
    <constructor-arg ref="httpConnectionManager"/>
</bean>
<bean class="org.springframework.http.client.CommonsClientHttpRequestFactory" id="httpClientFactory">
    <constructor-arg ref="httpClient"/>
</bean>
<bean class="org.springframework.security.oauth.consumer.client.OAuthRestTemplate" id="restTemplate">
    <constructor-arg ref="httpClientFactory"/>
    <constructor-arg ref="myResource"/>
    <property name="messageConverters">
        <list>
            <ref bean="marshallingHttpMessageConverter"/>
        </list>
    </property>
</bean>

请注意我使用的是OAuthRestTemplate,而myResource指的是我省略的oauth资源,因为它不相关。而不是OAuthRestTemplate你可以很容易地使用org.springframework.web.client.RestTemplate http://docs.spring.io/spring/docs/3.2.4.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html

另一答案

一个RestTemplate is thread safe once constructed,所以你可以构建一个实例并让你的所有任务共享它。这样会更有效率,因为您可以消除每项任务的构建成本,并减少垃圾收集器的负载。

以上是关于如何在多线程环境中有效地使用RestTemplate?的主要内容,如果未能解决你的问题,请参考以下文章

安全地使用 auto_ptr 交换对象而不锁定在多线程环境中?

如何在多线程程序中传递或共享开放流引用?

多线程环境中的扩展 OVERLAPPED 对象池:在何处以及如何有效地使用锁定

malloc 如何在多线程环境中工作?

如何使用 Java 在多线程环境中测试某些东西 [重复]

如何保护可能在多线程或异步环境中使用的资源?