【发布时间】:2014-02-03 07:13:43
【问题描述】:
我在我的代码中使用 Java Callable Future。下面是我使用未来和可调用对象的主要代码 -
public class TimeoutThread {
public static void main(String[] args) throws Exception {
// starting the background thread
new ScheduledCall().startScheduleTask();
ExecutorService executor = Executors.newFixedThreadPool(5);
Future<String> future = executor.submit(new Task());
try {
System.out.println("Started..");
System.out.println(future.get(3, TimeUnit.SECONDS));
System.out.println("Finished!");
} catch (TimeoutException e) {
System.out.println("Terminated!");
}
executor.shutdownNow();
}
}
下面是我的Task类,它实现了Callable接口,这个类需要从ClientData类方法中获取数据。我有一个后台线程,它使用 setter 设置 ClientData 类中的数据。
class Task implements Callable<String> {
public String call() throws Exception {
//.. some code
String hostname = ClientData.getPrimaryMapping("some_string").get(some_number);
//.. some code
}
}
下面是我的后台线程,它通过解析来自 URL 的数据来设置我的 ClientData 类中的值,它每 10 分钟运行一次。
public class ScheduledCall {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public void startScheduleTask() {
final ScheduledFuture<?> taskHandle = scheduler.scheduleAtFixedRate(
new Runnable() {
public void run() {
try {
callServers();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}, 0, 10, TimeUnit.MINUTES);
}
private void callServers() {
String url = "url";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
parseResponse(response);
}
// parse the response and set it.
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);
}
}
下面是我的ClientData类
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);
}
}
问题陈述:-
我面临的唯一问题是,每当我第一次启动程序时,会发生什么,它将启动后台线程,该线程将解析来自 URL 的数据。同时,它将进入我的Task 类的call 方法。下面的行会抛出异常,为什么?因为我的后台线程仍在解析数据,它还没有设置那个变量。
String hostname = ClientData.getPrimaryMapping("some_string").get(some_number);
如何避免这个问题?有没有更好更有效的方法来做到这一点?
【问题讨论】:
标签: java multithreading thread-safety executorservice scheduledexecutorservice