Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在多线程应用程序中有效地使用RestTemplate?_Java_Multithreading_Spring_Apache Httpclient 4.x_Resttemplate - Fatal编程技术网

Java 如何在多线程应用程序中有效地使用RestTemplate?

Java 如何在多线程应用程序中有效地使用RestTemplate?,java,multithreading,spring,apache-httpclient-4.x,resttemplate,Java,Multithreading,Spring,Apache Httpclient 4.x,Resttemplate,我正在我的一个库中使用restemplate作为我的HttpClient。我不确定我是否在多线程环境中正确使用它,因为我的库将在多线程环境中的非常重的负载下使用,所以它必须非常快 下面是我的DataClient类: public class DataClient implements Client { private RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory()); private

我正在我的一个库中使用
restemplate
作为我的
HttpClient
。我不确定我是否在多线程环境中正确使用它,因为我的库将在多线程环境中的非常重的负载下使用,所以它必须非常快

下面是我的DataClient类:

public class DataClient implements Client {

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

    // for synchronous call
    @Override
    public DataResponse executeSync(DataKey key) {
        DataResponse dataResponse = null;
        Future<DataResponse> future = null;

        try {
            future = executeAsync(key);
            dataResponse = future.get(key.getTimeout(), TimeUnit.MILLISECONDS);
        } catch (TimeoutException ex) {
            dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT, DataStatusEnum.ERROR);
            future.cancel(true);
        } catch (Exception ex) {
            dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
        }

        return dataResponse;
    }

    //for asynchronous call
    @Override
    public Future<DataResponse> executeAsync(DataKey key) {
        Future<DataResponse> future = null;
        Task task = new Task(key, restTemplate);
        future = executor.submit(task);

        return future;
    }

    // does this looks right?
    private ClientHttpRequestFactory clientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        // setting 2000 ms as the default timeout for each Http Request
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(2000).setConnectTimeout(2000)
                .setSocketTimeout(2000).setStaleConnectionCheckEnabled(false).build();
        SocketConfig socketConfig = SocketConfig.custom().setSoKeepAlive(true).setTcpNoDelay(true).build();

        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
        poolingHttpClientConnectionManager.setMaxTotal(800);
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(700);

        CloseableHttpClient httpClientBuilder = HttpClientBuilder.create()
                .setConnectionManager(poolingHttpClientConnectionManager).setDefaultRequestConfig(requestConfig)
                .setDefaultSocketConfig(socketConfig).build();

        requestFactory.setHttpClient(httpClientBuilder);
        return requestFactory;
    }
}
这就是我打电话获取数据的方式:

DataResponse response = DataClientFactory.getInstance().executeSync(dataKey);
现在我的问题是-我不确定我是否正确地将
restemplate
用于
httpcomponents客户端httprequestfactory
。我是否需要在这里使用
poollighttpclientconnectionmanager
restemplate


我的主要目标是在多线程环境中高效地使用
restemplate
。因为我的图书馆将在非常重的负载下使用,所以它必须非常快。在重载情况下,我看到了大量等待连接的时间,因此我添加了
clienthttpprequestfactory()
方法,用于
restemplate

restemplate
是在春季。因此,您可能需要在应用程序中只创建一个
restemplate
实例,并跨多个线程共享它。当然,这是假设您将为所有用户使用相同的HTTP属性(如超时、设置活动等)。如果您需要更改连接属性,您可以在应用程序开始时在
restemplate
对象中创建一个池,并使用该池将restemplate实例注入调用方类。

如果您对restemplate执行的所有请求都将通过executor
ExecutorService executor=Executors.newFixedThreadPool(10),然后通过这种方式自己管理restTemplate连接池。
public class DataClientFactory {

    private DataClientFactory() {}

    private static class ClientHolder {
        private static final DataClient INSTANCE = new DataClient();
    }

    public static Client getInstance() {
        return ClientHolder.INSTANCE;
    }
}
不需要其他连接管理器

但是,如果您使用带有所有必要配置(超时、连接号等)的
PoollightTPClientConnectionManager
会更好

结果,您编写的代码更少,因为您不再需要固定线程池执行器, 因为您在restTemplate上执行的每一个请求都将作为(您在上面所做的)获得:

final Future=this.pool.lease(..)

最后,如果您需要异步调用,也许值得一试。

。但是,我注意到您的
私有RestTemplate RestTemplate
不是
最终版
。因此,不清楚它是否来自
DataClient
的构造函数。引用永远不会更改,因此您可以简单地将其更改为
final
。幸运的是,在您的任何任务尝试使用它之前,引用都是可以使用的,因为
ExecutorService
提供了这样的保证,所以我相信您的代码是线程安全的。

我已经创建了
restemplate
的一个实例,对吗?我已经稍微更新了它,它告诉我们我是如何使用DataClient类的。因此,我对所有调用使用相同的HTTP属性。你能再看看我的问题吗?我看到你正在为同步调用创建一个新线程。基本上是浪费了创建一个新线程的成本。请看。
DataResponse response = DataClientFactory.getInstance().executeSync(dataKey);
final Future<CPoolEntry> future = this.pool.lease(..)