2

I have JList using DefaultListModel to update the strings in list in UI , returned by a class as shown

class ResponseGiver implements Callable<Future>{

        int i;

       //Constructor to initialize i

     String call(){
      ...............
      ...............
      return i;
  }

and i have other class that will update the results obtained from above

class Viewer {

    ExecutorService es = new Executors.newFixedThreadPool(10);
    List<Future<String>> futures = new ArrayList<Future<String>>();
    for(int i =0;i<10;i++)
      {
         futures.add(new ResponseGiver(i));
      }
 for(Future<String> x : futures)  //loop 2nd will be called 10 times
  {
     String p = x.get(); 
       //update GUI with p
   }

Now the question is, suppose in loop 2nd , in the 5th loop, the get() function takes some time say 10 seconds, and during the mean time, the other futures from 6th to 10th have their result ready. So my screen would wait for 5th result, even 6th to 10th are ready. I want my screen to be updated as soon as any of the 10 futures return the result.

4

2 回答 2

1

使用标准 API,您可以使用ExecutorCompletionService。它允许提交Callable实例并返回Future对象,就像普通的ExecutorService. 但它还允许Future按完成顺序获取对象:使用ExecutorCompletionService#take()方法。此方法会阻塞,直到有新Future的可用。您可以将其想象为Futures被放入阻塞队列中。

Future您可以从完成服务启动一个使用这些对象的线程。Future然后可以使用这样的结果来更新 GUI。(请注意,此更新又必须在 Event Dispatch Thread 上使用 再次完成SwingUtilities.invokeLater)。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class ExecutorCompletionServiceTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        f.getContentPane().setLayout(new BorderLayout());

        JButton button = new JButton("Run");
        f.getContentPane().add(button, BorderLayout.NORTH);

        final DefaultListModel<String> listModel = new DefaultListModel<String>();
        JList<String> list = new JList<String>(listModel);
        f.getContentPane().add(new JScrollPane(list), BorderLayout.CENTER);

        final Callback callback = new Callback()
        {
            @Override
            public void call(final String result)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        listModel.addElement(result);
                    }
                });
            }
        };

        button.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                createTasks(callback);
            }
        });

        f.setSize(300, 300);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    interface Callback
    {
        void call(String result);
    }


    private static Random random = new Random(0);

    static class ResponseGiver implements Callable<String>
    {
        private int i;

        ResponseGiver(int i)
        {
            this.i = i;
        }

        @Override
        public String call()
        {
            int delayMS = 250 + random.nextInt(500);

            // Simulate a longer delay for task 5
            if (i == 5)
            {
                delayMS += 3000;
            }
            try
            {
                System.out.println("For "+i+" waiting "+delayMS+" ms");
                Thread.sleep(delayMS);
                System.out.println("For "+i+" waiting "+delayMS+" ms DONE");
            }
            catch (InterruptedException e)
            {
                Thread.currentThread().interrupt();
            }
            return String.valueOf(i);
        }
    }

    private static void createTasks(final Callback callback)
    {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        final CompletionService<String> executorCompletionService =
            new ExecutorCompletionService<String>(executorService);
        final int n = 10;
        for (int i = 0; i < 10; i++)
        {
            executorCompletionService.submit(new ResponseGiver(i));
        }
        Thread thread = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                processResults(executorCompletionService, n, callback);
            }
        });
        thread.start();
    }

    private static void processResults(
        CompletionService<String> completionService, int n, Callback callback)
    {
        for (int i = 0; i < n; i++)
        {
            try
            {
                Future<String> future = completionService.take();
                String result = future.get();
                if (result != null)
                {
                    callback.call(result);
                }
                System.out.println("Processed "+(i+1)+" of "+n+" results");
            }
            catch (InterruptedException e)
            {
                Thread.currentThread().interrupt();
            }
            catch (ExecutionException e)
            {
                e.printStackTrace();
            }
        }
    }
}
于 2014-05-18T14:54:15.603 回答
0

只需使用ListenableFuture番石榴。方便多了。

于 2012-12-05T14:30:13.273 回答