【发布时间】:2014-01-14 21:25:59
【问题描述】:
下面是我的工厂代码,它启动后台线程TempScheduler -
public class TempClientFactory {
public static IClient getInstance() {
new TempScheduler().startScheduler();
return ClientHolder.INSTANCE;
}
private static class ClientHolder {
private static final TempClient INSTANCE = new TempClient();
}
}
现在客户将像这样使用上述工厂调用我们的代码。他们只会获取我们的 Client 实例一次,然后使用该实例在我的实现中调用 read 方法 -
IClient client = TempClientFactory.getInstance();
String response = client.read(userId);
下面是我的后台线程代码,它将从 URL 中获取数据,对其进行解析并将其存储在类变量中 -
public class TempScheduler {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public void startScheduler() {
final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
try {
callServers();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}, 0, 10, TimeUnit.MINUTES);
}
}
// call the servers and get the data and then parse
// the response.
private void callServers() {
String url = "url";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
parseResponse(response);
}
// parse the response and store it in a variable
private void parseResponse(String response) {
//...
ConcurrentHashMap<String, Map<Integer, String>> primaryTables = null;
//...
// store the data in ClientData class variables which can be
// used by other threads
ClientData.setPrimaryMapping(primaryTables);
}
}
解析来自 URL 的数据后,我上面的后台线程将使用其设置器将结果存储在我的类 ClientData 的变量中。下面是我的ClientData class。
public class ClientData {
private static final AtomicReference<Map<String, Map<Integer, String>>> primaryMapping = new AtomicReference<>();
public static Map<String, Map<Integer, String>> getPrimaryMapping() {
return primaryMapping.get();
}
public static void setPrimaryMapping(Map<String, Map<Integer, String>> map) {
primaryMapping.set(map);
}
}
问题陈述:-
现在有趣的部分来了,正如您所看到的,客户将使用上述工厂调用我们的代码,一旦他们调用 getInstance() 方法,我的后台线程就会启动,它将从URL 然后解析它并将其存储在类变量中。但是在执行getInstance() 方法后,他们会立即在我的客户端代码中调用read method..
然后我应该使用我的后台线程在我的实现代码中设置的变量。我的具有read 方法的实现代码使用CallableTaks 和future.get,所以它会自动来到下面的call 方法。在下面的类中,我应该使用由后台线程设置的变量值。我需要使用getPrimaryMapping 方法来获取下面代码中的值。
public class ClientTask implements Callable<String> {
private String userId = null;
public ClientTask(String userId) {
this.userId = userId;
}
@Override
public String call() throws Exception {
//.....
String hostname = ClientData.getPrimaryMapping("some_string").get(some_number);
//....
}
}
这种方法的问题是,一旦客户第一次调用我们的工厂获取实例,它就会启动后台线程,该线程将从 URL 中获取数据并解析它并将数据存储在一个类变量,但它会立即调用我的实现类的read 方法..
现在可能第一次,我的后台线程仍在解析数据,但实际调用已经进入 call method 内部,然后它会尝试从 getPrimaryMapping 方法获取数据但它赢了什么都没有,对吧?为什么 bcoz 它仍在解析数据.. 那么我如何确保当客户第一次调用我们的代码时,一旦解析完成,然后只允许在调用方法中获取变量值。
然后第二次就好了..由于数据会在内存中,只有第一次是问题..
有什么办法吗?
【问题讨论】:
标签: java multithreading executorservice futuretask scheduledexecutorservice