Java 当数据可用时,如何从地图中获取数据?
我在代码中使用Java可调用的Future。下面是我使用future和callables的主要代码-Java 当数据可用时,如何从地图中获取数据?,java,multithreading,thread-safety,executorservice,scheduledexecutorservice,Java,Multithreading,Thread Safety,Executorservice,Scheduledexecutorservice,我在代码中使用Java可调用的Future。下面是我使用future和callables的主要代码- public class TimeoutThread { public static void main(String[] args) throws Exception { // starting the background thread new ScheduledCall().startScheduleTask(); Execut
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();
}
}
下面是我的后台线程,它通过解析来自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);
}
}
问题陈述:-
我面临的唯一问题是,每当我第一次启动程序时,它都会启动后台线程,该线程将解析来自URL的数据。同时,它将进入我的任务
类的调用
方法。下面的一行将抛出异常,为什么?bcoz我的后台线程仍在解析数据,并且没有设置该变量
String hostname = ClientData.getPrimaryMapping("some_string").get(some_number);
我如何避免这个问题?有没有更好、更有效的方法来完成此任务?您只想让任务等待,直到地图的第一次更新完成后再继续
public class ClientData {
private static final AtomicReference<Map<String, Map<Integer, String>>> primaryMapping = new AtomicReference<>();
private static final CountDownLatch hasBeenInitialized = new CountDownLatch(1);
public static Map<String, Map<Integer, String>> getPrimaryMapping() {
try {
hasBeenInitialized.await();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return primaryMapping.get();
}
public static void setPrimaryMapping(Map<String, Map<Integer, String>> map) {
primaryMapping.set(map);
hasBeenInitialized.countDown();
}
}
公共类ClientData{
私有静态最终AtomicReference primaryMapping=新的AtomicReference();
私有静态最终CountDownLatch已初始化=新CountDownLatch(1);
公共静态映射getPrimaryMapping(){
试一试{
已初始化。等待();
}捕捉(中断异常e){
抛出新的非法状态异常(e);
}
返回primaryMapping.get();
}
公共静态void setPrimaryMapping(映射映射){
primaryMapping.set(map);
已初始化。倒计时();
}
}
一种更简单、更有效的方法是,在启动多线程引擎之前,只需将初始值加载到映射中,就可以避免同步检查并处理愚蠢的InterruptedException(被检查的异常)。假设我在
ClientData
类中有多个字段,那么我需要在所有这些getter和setter中执行与您在建议中所做的相同的操作?这是一个选项,是的。由于不知道程序的实际功能,我个人可能只是在那一点上加载一些初始值。。由于某种原因,一旦启动应用程序,就无法初始化该值。在这个场景中还有一件事,当我从getPrimaryMapping
检索值时,我的主线程将始终等待,或者当我启动应用程序时,它将只等待第一次?如果我问了一个愚蠢的问题,请原谅。这是我第一次使用CountDownLatch
工作,所以我对它了解不多。。如果你能解释一下这在我当前的场景中是如何工作的,我将能够理解CountDownLatch是如何工作的。。谢谢..任何调用getPrimaryMapping的线程都将无限期阻塞,直到其他线程调用setPrimaryMapping。一旦集合被调用至少一次,就不会再发生阻塞。谢谢你。只是一个随机的问题。这是否也适用于同步方法?假设我放置同步的getter和setter方法,而不是使用CountDownLatch
。那么它会起作用吗?
String hostname = ClientData.getPrimaryMapping("some_string").get(some_number);
public class ClientData {
private static final AtomicReference<Map<String, Map<Integer, String>>> primaryMapping = new AtomicReference<>();
private static final CountDownLatch hasBeenInitialized = new CountDownLatch(1);
public static Map<String, Map<Integer, String>> getPrimaryMapping() {
try {
hasBeenInitialized.await();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return primaryMapping.get();
}
public static void setPrimaryMapping(Map<String, Map<Integer, String>> map) {
primaryMapping.set(map);
hasBeenInitialized.countDown();
}
}