0

コードで 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();
    }
}

以下はTaskCallable インターフェースを実装する私のクラスで、このクラスはClientDataクラスメソッドからデータを取得する必要があります。ClientDataまた、セッターを使用してクラスにデータを設定するバックグラウンド スレッドがあります。

class Task implements Callable<String> {

    public String call() throws Exception {

    //.. some code

    String hostname = ClientData.getPrimaryMapping("some_string").get(some_number);

    //.. some code
    }
}

ClientData以下は、URL からのデータを解析してクラスに値を設定するバックグラウンド スレッドで、 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 からのデータを解析するバックグラウンド スレッドを開始することです。同時に、それは私のクラスcallのメソッドに入ります。Taskそして、以下の行は例外をスローします。なぜですか? bcoz 私のバックグラウンド スレッドはまだデータを解析しており、その変数を設定していません。

String hostname = ClientData.getPrimaryMapping("some_string").get(some_number);

この問題を回避するにはどうすればよいですか? これを行うためのより良い効率的な方法はありますか?

4

1 に答える 1

2

続行する前に、マップへの最初の更新が発生するまでタスクを待機させたいだけですか?

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

同期チェックを発生させず、愚かな InterruptedException が Checked Exception であることを処理するより単純で効率的な方法は、マルチスレッド エンジンを起動する前に、単純に初期値を Map にロードすることかもしれません.....

于 2014-01-15T00:48:17.737 に答える