【问题标题】:Java Threading: Futures only using results from first and last threadJava 线程:期货仅使用第一个和最后一个线程的结果
【发布时间】:2013-04-03 18:03:38
【问题描述】:

我有一个简单的实用程序,它 ping 一组节点并将字符串的 ArrayList 返回到将来的对象以输出到文件。程序应该一直运行,直到被用户终止。

未来似乎没有收到结果(或至少将它们传递给方法以输出到文件)。无论我同时运行的线程数(总是小于 100,由输入文件确定),我只输出第一个和最后一个初始化线程的结果。

作为健全性检查,我创建了一个全局变量,每个线程将在其中发送其结果,然后关闭并将其结果返回给 Future 对象。这个变量被所有线程正确更新。

有人知道为什么 Future 似乎没有从线程中收到我所有的结果吗?

public class PingUtility{
    public static ExecutorService pool = Executors.newFixedThreadPool(100);
    static Future<ArrayList<String>> future;

    public static void main(String[] args) throws Exception {

        Timer timer = new Timer();
        TimerTask task = new TimerTask(){
            public void run(){
                //Creates a pool of threads to be executed
                ArrayList<String[]> nodes = new ArrayList<String[]>()
                future = pool.submit(new PingNode(nodes));
                }   
            }
        };

        timer.scheduleAtFixedRate(task, 0, interval);

        while(true){
            try{
                ArrayList<String[]> tempOutputArray = future.get();
                Iterator<String[]> it = tempOutputArray.iterator();
                while(it.hasNext()) appendFile(it.next());
                tempOutputArray.clear();
            }catch(Exception nullException){
            //Do nothing
            }
        }
    }

【问题讨论】:

  • 为了后代,您应该始终记录异常(尤其是 NPE)。如果迭代器可以获得null,那么您应该在代码中处理它。

标签: java multithreading concurrency future


【解决方案1】:

您的问题是您正在修改定时器任务线程中的future 静态字段没有同步并在主线程中读取它。您需要在修改时对其进行同步读取它,或者使用其他机制在线程之间共享信息。

我建议从static 字段切换到LinkedBlockingQueue,作为将信息从PingNode 调用发送到appendFile(...) 方法的更好方法。这样可以避免需要自己进行同步,并防止多个计时器任务将启动并覆盖future,然后消费者才能从它们get()。可能是这样的:

 BlockingQueue<String[]> queue = new LinkedBlockingQueue<String[]>();
 ...

 // inside of run, producer passes the queue into the PingNode
 public void run() {
     pool.submit(new PingNode(queue));
 }

 // consumer
 while (true) {
     String[] array = queue.take();
     ...
 }

这不会影响您在完成后停止线程的方式。如果计时器任务被终止,实体可以向队列中添加终止对象以停止主循环。

【讨论】:

  • 谢谢,我将不得不研究一下以了解如何正确实施它。
  • 我的意思是排队 String[]。所以在你的例子中,我根本不会使用未来?队列是否用于存储 PingNode 的结果?如果是这样,我想我需要修改方法以同时使用输入和队列来处理输出?
  • 是的,不需要使用Future。我考虑过推荐BlockingQueue&lt;Future&gt;,但这似乎没有必要。您将List 传递给PingNode,因此直接传递queue 是有意义的。
  • 感谢您的帮助,我很容易就搞定了
【解决方案2】:

Future 对象不像 ArrayList 那样是 bin,它只是指向单个计算结果。因为你只有一个指向这个 Future 的静态指针,所以我想发生的事情是这样的:

    future = null
    nullException
    nullException
    nullException
    nullException
    ...
    First thread finally sets future = Future<ArrayList<String>>
    Call to future.get() blocks...
        Meanwhile, all other threads get scheduled, and they reassign future
        The last thread will obviously get the last say in what future points to
    Data is gathered, written to file, loop continues
    future now points to the Future from the last thread
    Results from last thread get printed

【讨论】:

  • 谢谢,这听起来像是发生了什么。你会推荐上面的 LinkedBlockingQueue 吗?有没有办法通过将结果放在一个类似对象的容器中来适当地处理结果,我只是抓住第一个结果,处理它然后继续下一个?
  • 这就是 LinkedBlockingQueue 的作用。将 put() 放入队列的线程会阻塞,直到另一个线程 poll() 来自它,同样,一个 poll() 来自它的线程将挂起,直到另一个线程 put() 一些东西。
猜你喜欢
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-31
  • 2016-02-29
  • 2013-01-23
  • 1970-01-01
相关资源
最近更新 更多