noo*_*oob 6 java concurrency multithreading
我有一个webservice调用来获取授权令牌并将其用于后续的webservice调用.现在我们之前做的是每当我们进行任何Web服务调用时,我们首先制作令牌Web服务,然后调用实际的Web服务.
获取令牌的方法如下所示.基本上,这段代码的作用是调用webservice来获取令牌,并使用GSON解析响应并获取令牌.
public static String getAuthTicket() {
String authTicket = null;
HttpResponse httpResponse = getAuthResponse();
String body;
if (httpResponse.getStatusLine().getStatusCode() == 200) {
try {
body = IOUtils.toString(httpResponse.getEntity().getContent());
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
ResponseTicket responseTicket = gson.fromJson(body, ResponseTicket.class);
authTicket = responseTicket.getTicket();
} catch (UnsupportedOperationException e) {
LOGGER.error("UnsupportedOperationException : ",e);
} catch (IOException e) {
LOGGER.error("IO Exception : ",e);
}
}
return authTicket;
}
Run Code Online (Sandbox Code Playgroud)
这显然导致了性能问题.因此,提供Web服务以获取令牌的一方使令牌有效30分钟.
所以在上面的方法中我们想到的是将令牌与时间一起放入缓存并检查当前时间 - 缓存时间是否小于30.如果时间大于30,我们将进行服务调用以获取令牌并更新缓存中带有时间戳的令牌.
唯一的问题是我担心的是同步,所以我不会因为竞争条件而变得腐败.
我想将这个静态方法设为同步.你认为还有其他更好的方法吗?
答案是:这取决于.
当多个线程在同一时间点访问共享数据时,会出现竞争条件.所以,当你有代码时,如:
private final Map<X, Y> sharedCache = new HashMap<>();
public static getAuthTicket() {
if (! sharedCache.containsKey...) {
sharedCache.put(...
...
Run Code Online (Sandbox Code Playgroud)
您将受到竞争条件的影响 - 两个线程可以同时进入,并在同一时间更新共享地图; 导致各种问题.
当我得到你的代码时 - 你会有类似的东西:
private static String cachedToken = null;
public static getAuthTicket() {
if (cachedToken == null || isTooOld(cachedToken)) {
cachedToken = getAuthTicketForReal();
}
return cachedToken;
}
Run Code Online (Sandbox Code Playgroud)
您可能不希望两个线程getAuthTicketForReal()并行调用.
所以,是的,使该方法同步是一种有效的方法.
其中:真正的问题是:添加该关键字是否足够?鉴于我的代码 - 答案是肯定的.您只是想避免此缓存由多个线程"并行"设置.
最后:如果您担心在这里使用synchronized会对性能产生影响- 请忘记这一点.你在谈论一个多秒的"基于网络"的操作; 所以你绝对不要担心同步可能产生的毫秒开销(构成这个数字 - 关键是:它太小了,在你正在进行的操作的上下文中并不重要).
关于你的评论:当然,使用synchronized意味着JVM将序列化对该方法的调用.这意味着当此方法需要1分钟返回时 - 对该方法的任何其他调用将阻止该1分钟.
从这个意义上说; 它可能是一个很好的锻炼寻找到撰写中,它的方式这种方法方式不要求同步的方法的水平.例如,通过使用可以处理操作它们的多个线程的数据结构.