【问题标题】:Java ScheduledFuture get ListJava ScheduledFuture 获取列表
【发布时间】:2018-01-12 08:52:02
【问题描述】:

此代码总是返回 10。我认为接收所有功能列表的问题。当变量限制等于 5 时,我需要解析每个功能并停止执行调度程序。我该怎么做?

static int limit = 0;
static final int testNum = 10;

static ScheduledExecutorService scheduler;
public static void main(String[] args) {
    scheduler = Executors
            .newScheduledThreadPool(5);
    ScheduledFuture<Integer> future = scheduler.schedule(new ScheduledPrinter(), 10, TimeUnit.SECONDS);
    try {
        while (true) {
            System.out.println(future.get());
            if(future.get() != testNum){
                return;
            }
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}
private static class ScheduledPrinter implements Callable<Integer> {
    public Integer call() throws Exception {
        limit++;
        if(limit==5) {
            scheduler.shutdown();
            return limit;
        }
        return testNum;
    }
}

【问题讨论】:

    标签: java multithreading scheduling futuretask


    【解决方案1】:

    让我们看看这里发生了什么。 scheduler.schedule(new ScheduledPrinter(), 10, TimeUnit.SECONDS) 只运行一次 ScheduledPrinter.call()Here 是 API 文档。

    您想要的可能是scheduleAtFixedRate。这需要 Runnable 而不是可调用的,因此代码将如下所示:

    static volatile int limit = 0; // make it volatile because of *possible* multithreaded access
                                   // an AtomicInteger would do too
    static final int testNum = 10;
    
    static ScheduledExecutorService scheduler;
    
    public static void main(String[] args) {
        scheduler = Executors
                .newScheduledThreadPool(5);
        // discarding the future. No need to use it here.
        ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(new ScheduledPrinter(), 10L, 10L, TimeUnit.SECONDS);
    }
    
    /** Printing and counting happens here **/
    private static class ScheduledPrinter implements Runnable {
    
        @Override
        public void run() {
            limit++;
            if(limit==5) {
                scheduler.shutdown();
                printNum(limit);
            } else {
                printNum(testNum);
            }
        }
    
        private void printNum(int num) {
            System.out.println(num);
        }
    }
    

    更新

    OP 询问如何从Runnable.run() 方法返回值?不幸的是,这是不可能的。我们必须在定期运行和返回值之间进行选择,因为ScheduledExecutorService 不能同时做到这两者。

    仍然可以从Runnable 中获取值。我们必须为此分享一个参考。这是一个基本的方法:

        final Queue<Integer> numsPrinted = new ConcurrentLinkedQueue<>(); // a concurrent collection
        ScheduledFuture<?> future = scheduler.scheduleWithFixedDelay( // using scheduleWithFixedDelay because probably this is what you want
                new ScheduledPrinter(numsPrinted), // passing the reference
                10L, 10L, TimeUnit.SECONDS);
        try {
            future.isDone();
            Object obj = future.get(80, TimeUnit.SECONDS); // blocks until 80 secs or until the task is done
            System.out.println(obj);
            System.out.println(Arrays.toString(numsPrinted.toArray()));
        } catch (TimeoutException e) {
            System.out.println(Arrays.toString(numsPrinted.toArray()));
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } 
    

    ScheduledPrinter 现在看起来像这样:

    private static class ScheduledPrinter implements Runnable {
    
        private final Queue<Integer> numsPrinted;
    
        public ScheduledPrinter(Queue<Integer> numsPrinted) {
            this.numsPrinted = numsPrinted; // storing the reference
        }
    
        @Override
        public void run() {
            limit++;
            if(limit==5) {
                //scheduler.awaitTermination(timeout, unit)
                scheduler.shutdown();
                storeAndPrintNum(limit);
            } else {
                storeAndPrintNum(testNum);
            }
        }
    
        private void storeAndPrintNum(int num) {
            numsPrinted.add(num); // using the reference
            System.out.println(num);
        }
    }
    

    【讨论】:

    • 谢谢!它适合我,但如果我想从 Runnable 中的 run() 返回一些值。我该怎么做?
    • 简短的回答是你不能同时获得返回值和重复发生的事件。长答案在更新的答案中:)
    【解决方案2】:

    ScheduledPrinter.call() 方法只被调用一次,在 while 循环中,您总是返回计算一次的值。因此limit永远不会增加,并且永远不会调用shutdown。所以我认为你需要改变逻辑,也许运行更多线程。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 2020-11-25
      • 2014-09-28
      相关资源
      最近更新 更多