Java线程:期货只使用第一个和最后一个线程的结果

时间:2013-04-11 13:50:46

标签: java multithreading concurrency future

我有一个简单的实用程序,它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
            }
        }
    }

2 个答案:

答案 0 :(得分:3)

您的问题是您正在修改计时器任务线程中的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();
     ...
 }

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

答案 1 :(得分:0)

Future对象不是bin,就像ArrayList一样,它只指向单个计算结果。因为你只有一个指向这个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