Java 当数据可用时,如何从地图中获取数据?

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

我在代码中使用Java可调用的Future。下面是我使用future和callables的主要代码-

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();
    }
}