我正在开发一个项目,我需要在其中使用java客户端的同步和异步方法。有些客户会调用同步,有些客户会根据需要调用我的java客户端的异步方法。
以下是我的java客户端,其中包含synchronous
和asynchronous
方法 -
public class TestingClient implements IClient {
private ExecutorService service = Executors.newFixedThreadPool(10);
private RestTemplate restTemplate = new RestTemplate();
// for synchronous
@Override
public String executeSync(ClientKey keys) {
String response = null;
try {
Future<String> handle = executeAsync(keys);
response = handle.get(keys.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
} catch (Exception e) {
}
return response;
}
// for asynchronous
@Override
public Future<String> executeAsync(ClientKey keys) {
Future<String> future = null;
try {
ClientTask ClientTask = new ClientTask(keys, restTemplate);
future = service.submit(ClientTask);
} catch (Exception ex) {
}
return future;
}
}
现在下面是我的ClientTask
类,它实现了Callable接口,我使用ClientTask class
中的DI模式传递依赖关系。在call方法中,我只是在machineIPAddress
上创建一个URL基础并使用ClientKeys
传递给ClientTask
类,然后使用RestTemplate
命中服务器并获取回复 -
class ClientTask implements Callable<String> {
private ClientKey cKeys;
private RestTemplate restTemplate;
public ClientTask(ClientKey cKeys, RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.cKeys = cKeys;
}
@Override
public String call() throws Exception {
// .. some code here
String url = generateURL("machineIPAddress");
String response = restTemplate.getForObject(url, String.class);
return response;
}
// is this method thread safe and the way I am using `cKeys` variable here is also thread safe?
private String generateURL(final String hostIPAdress) throws Exception {
StringBuffer url = new StringBuffer();
url.append("http://" + hostIPAdress + ":8087/user?user_id=" + cKeys.getUserId() + "&client_id="
+ cKeys.getClientId());
final Map<String, String> paramMap = cKeys.getParameterMap();
Set<Entry<String, String>> params = paramMap.entrySet();
for (Entry<String, String> e : params) {
url.append("&" + e.getKey());
url.append("=" + e.getValue());
}
return url.toString();
}
}
以下是使用Builder模式的ClientKey
类,客户将使用该模式将输入参数传递给TestingClient
-
public final class ClientKey {
private final long userId;
private final int clientId;
private final long timeout;
private final boolean testFlag;
private final Map<String, String> parameterMap;
private ClientKey(Builder builder) {
this.userId = builder.userId;
this.clientId = builder.clientId;
this.remoteFlag = builder.remoteFlag;
this.testFlag = builder.testFlag;
this.parameterMap = builder.parameterMap;
this.timeout = builder.timeout;
}
public static class Builder {
protected final long userId;
protected final int clientId;
protected long timeout = 200L;
protected boolean remoteFlag = false;
protected boolean testFlag = true;
protected Map<String, String> parameterMap;
public Builder(long userId, int clientId) {
this.userId = userId;
this.clientId = clientId;
}
public Builder parameterMap(Map<String, String> parameterMap) {
this.parameterMap = parameterMap;
return this;
}
public Builder remoteFlag(boolean remoteFlag) {
this.remoteFlag = remoteFlag;
return this;
}
public Builder testFlag(boolean testFlag) {
this.testFlag = testFlag;
return this;
}
public Builder addTimeout(long timeout) {
this.timeout = timeout;
return this;
}
public ClientKey build() {
return new ClientKey(this);
}
}
public long getUserId() {
return userId;
}
public int getClientId() {
return clientId;
}
public long getTimeout() {
return timeout;
}
public Map<String, String> getParameterMap() {
return parameterMap;
public boolean istestFlag() {
return testFlag;
}
}
我的上述代码线程是否安全,因为我在多线程环境中的ClientKey
类中使用ClientTask
变量,所以不确定如果另一个线程在创建ClientKey
变量时会发生什么调用TestingClient
同步方法 -
因为客户会使用以下代码打电话给我们,他们也可以从那里打电话给我们多线程应用程序 -
IClient testClient = ClientFactory.getInstance();
Map<String, String> testMap = new LinkedHashMap<String, String>();
testMap.put("hello", "world");
ClientKey keys = new ClientKey.Builder(12345L, 200).addTimeout(2000L).parameterMap(testMap).build();
String response = testClient.executeSync(keys);
所以只是试着理解我的上面的代码是否是线程安全的,因为它们可以从多个线程将多个值传递给我的TestingClient
类。我感觉我的ClientKey
类由于parameterMap
而不是线程安全但不确定。
此外我还需要StringBuffer
或StringBuilder
会很好,因为StringBuilder比StringBuffer快,因为它不同步。
任何人都可以帮我吗?
答案 0 :(得分:1)
给出了参数ClientKey keys
,所以我假设总是不同。
我没有看到您的代码存在任何同步问题,我将解释:
ClientTask ClientTask = new ClientTask(keys, restTemplate);
future = service.submit(ClientTask);
ClientTask
对象,但不在线程之间共享。service.submit
,返回Future对象ClientTask
对象仅在方法generateURL
内读取密钥,但是,正如我之前所说,ClientKeys
对象是作为参数给出的,所以你很好此对象未被共享。总之,代码的线程安全性取决于ExecutorService
和Future
是否是线程安全的。
更新:as long as this object is not being shared
ClientKeys keys;
add keys to @keys
.. code
executeAsync(.., keys)
... code
add keys to @keys
add keys to @keys
executeAsync(.., keys)
executeAsync(.., keys)
add keys to @keys
... code
add keys to @keys
executeAsync(.., keys)
这是(越来越少)我的意思是分享。由于调用了executeAsync(),因此在几个线程中使用keys
。在这种情况下,一些线程正在读取keys
,而其他线程正在读取writing
数据,导致什么称为race condition。
更新2:StringBuffer
对象是generateURL
的本地对象(也在{{1}}范围内),无需同步它。