3

Whenever i run my program implementing callable, i get the output in a sequential form.

Like, here is my program :

package com.handson;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class WorkSheet_1 implements Callable<String> {

    /**
     * @param args
     */
    private int id;
    static int count = 0;
    public static String test[] = { "a1" , "a2" , "a3" , "a4" , "a5" , "a6" , "a7" , "a8" ,
                                    "b1" , "b2" , "b3" , "b4" , "b5" , "b6" , "b7" , "b8" ,
                                    "c1" , "c2" , "c3" , "c4" , "c5" , "c6" , "c7" , "c8" ,
                                    "d1" , "d2" , "d3" , "d4" , "d5" , "d6" , "d7" , "d8" ,
                                    "e1" , "e2" , "e3" , "e4" , "e5" , "e6" , "e7" , "e8" ,
                                    "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , "f8" ,
                                    "g1" , "g2" , "g3" , "g4" , "g5" , "g6" , "g7" , "g8" ,
                                    "h1" , "h2" , "h3" , "h4" , "h5" , "h6" , "h7" , "h8"}; 
    public WorkSheet_1(int id){
        this.id = id;
    }

    public static void main(String[] args) {
        try{
        // TODO Auto-generated method stub
            BlockingQueue blockingQueue = new ArrayBlockingQueue<WorkSheet_1>(48);
            ThreadPoolExecutor testExecutor = new ThreadPoolExecutor(6, 10, 1, TimeUnit.SECONDS, blockingQueue);
            for(int i = 0 ;i < test.length ;i++){
                Future<String> testFuture = testExecutor.submit(new WorkSheet_1(i));
                try {
                    System.out.println("Output Returned is : "+testFuture.get());
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }catch(RejectedExecutionException e){
            e.printStackTrace();
        }
    }

    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        return "Called "+test[this.id];
    }



}

CALLABLE OUTPUT :

Output Returned is : Called a1
Output Returned is : Called a2
Output Returned is : Called a3
Output Returned is : Called a4
Output Returned is : Called a5
Output Returned is : Called a6
Output Returned is : Called a7
Output Returned is : Called a8
Output Returned is : Called b1
Output Returned is : Called b2
Output Returned is : Called b3
Output Returned is : Called b4
Output Returned is : Called b5
Output Returned is : Called b6
Output Returned is ...............

Output always prints the array sequentially whereas when i implement runnable output is in any order :

RUNNABLE OUTPUT :

Output Returned is : Called a1
Output Returned is : Called a3
Output Returned is : Called a7
Output Returned is : Called a8
Output Returned is : Called b1
Output Returned is : Called b2
Output Returned is : Called b3
Output Returned is : Called b4 ..............

Why such a difference ?

4

3 回答 3

5

因为您在 for 循环中等待可调用的结果:

  System.out.println("Output Returned is : "+testFuture.get());

Future.get() 方法将阻塞,直到结果可用。因此,只有在上一个结果可用后,您才提交下一个 Callable。

于 2013-08-23T08:39:13.160 回答
4

要查看输出的交错,您需要进行两项更改。

第一个,基于前面的答案,是将等待完成的任务移出排队任务的循环。这样做允许 Callables 并行运行,而不是在每个 Callables 之后强制等待返回值。返回值仍然按照它们排队的顺序报告。

第二个变化是让每个 Callable 在运行时产生一些输出。如果只在完成时从主线程输出,则输出必须按照等待完成的顺序。

因为 Runnable 不产生返回值,所以我确信 Runnable 形式的测试实际上做了这两项更改。他们必须在运行时提供自己的输出,而不是返回结果。没有理由等待他们每个人完成。

这是一个基于原始程序的测试程序,具有这些更改:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test implements Callable<String> {

  /**
   * @param args
   */
  private int id;
  static int count = 0;
  public static String test[] = { "a1", "a2", "a3", "a4", "a5", "a6", "a7",
      "a8",
      "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8",
      "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8",
      "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8",
      "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8",
      "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8",
      "g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8",
      "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8" };

  public Test(int id) {
    this.id = id;
  }

  public static void main(String[] args) {
    try {
      // TODO Auto-generated method stub
      BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(
          48);
      ThreadPoolExecutor testExecutor = new ThreadPoolExecutor(6, 10, 1,
          TimeUnit.SECONDS, blockingQueue);
      List<Future<String>> futures = new ArrayList<>();
      for (int i = 0; i < test.length; i++) {
        Future<String> testFuture = testExecutor.submit(new Test(i));
        futures.add(testFuture);
      }
      for (Future<String> testFuture : futures) {
        try {
          System.out.println("Output Returned is : " + testFuture.get());
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        } catch (ExecutionException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    } catch (RejectedExecutionException e) {
      e.printStackTrace();
    }
  }

  @Override
  public String call() throws Exception {
    System.out.println("Running " + test[this.id]);
    return "Called " + test[this.id];
  }

}

样本输出:

Running a1
Running a3
Running a2
Running a4
Running a5
Running a6
Running a7
Running b1
Running b5
Running a8
Running b7
Running b6
Running b2
Running b4
Running b3
Running c4
Running c3
Running c2
Running c1
Running b8
Running d1
Running c8
Running c7
Running c6
Output Returned is : Called a1
Output Returned is : Called a2
Output Returned is : Called a3
Running c5
Output Returned is : Called a4
Running d6
Running d5
Running d4
Running d3
Running d2
Running e3
Running e2
Running e1
Running d8
Output Returned is : Called a5
Running d7
Output Returned is : Called a6
Running e8
Running e7
Running e6
Running e5
Running e4
Running f5
Running f4
Running f3
Running f2
Output Returned is : Called a7
Running f1
Output Returned is : Called a8
Running g2
Running g1
Running f8
Running f7
Running f6
Running g7
Running g6
Running g5
Running g4
Output Returned is : Called b1
Running g3
Output Returned is : Called b2
Running h4
Running h3
Running h2
Running h1
Running g8
Running h8
Running h7
Running h6
Output Returned is : Called b3
Running h5
Output Returned is : Called b4
Output Returned is : Called b5
Output Returned is : Called b6
Output Returned is : Called b7
Output Returned is : Called b8
Output Returned is : Called c1
Output Returned is : Called c2
Output Returned is : Called c3
Output Returned is : Called c4
Output Returned is : Called c5
Output Returned is : Called c6
Output Returned is : Called c7
Output Returned is : Called c8
Output Returned is : Called d1
Output Returned is : Called d2
Output Returned is : Called d3
Output Returned is : Called d4
Output Returned is : Called d5
Output Returned is : Called d6
Output Returned is : Called d7
Output Returned is : Called d8
Output Returned is : Called e1
Output Returned is : Called e2
Output Returned is : Called e3
Output Returned is : Called e4
Output Returned is : Called e5
Output Returned is : Called e6
Output Returned is : Called e7
Output Returned is : Called e8
Output Returned is : Called f1
Output Returned is : Called f2
Output Returned is : Called f3
Output Returned is : Called f4
Output Returned is : Called f5
Output Returned is : Called f6
Output Returned is : Called f7
Output Returned is : Called f8
Output Returned is : Called g1
Output Returned is : Called g2
Output Returned is : Called g3
Output Returned is : Called g4
Output Returned is : Called g5
Output Returned is : Called g6
Output Returned is : Called g7
Output Returned is : Called g8
Output Returned is : Called h1
Output Returned is : Called h2
Output Returned is : Called h3
Output Returned is : Called h4
Output Returned is : Called h5
Output Returned is : Called h6
Output Returned is : Called h7
Output Returned is : Called h8

“Running xx”消息开始时或多或少是按顺序排列的,但很快就会乱序。

于 2013-08-23T08:56:49.483 回答
2

使用CompletionService我们不需要Sysout在调用函数中打印(由@Patricia 提供)并且使用 CompletionService 比使用 Futures 有好处。

有关更多信息,请参阅java-concurrency-executors-and-thread-pools。该网站表示,

“使用future的代码有点复杂,有一个缺点,如果第一个任务计算时间长,其他任务都在第一个之前结束,当前线程无法在第一个任务结束之前计算结果。解决这个问题问题是完成服务”

现在使用完成服务的解决方案打印所需的结果:

    BlockingQueue<Runnable> blockingQueue   blockingQueue = new ArrayBlockingQueue<WorkSheet_1>(48);
    ThreadPoolExecutor testExecutor = new ThreadPoolExecutor(6, 16, 1,
            TimeUnit.SECONDS, blockingQueue, new CustomThreadFactory());

    CompletionService<String> completionService = new ExecutorCompletionService<String>(
            testExecutor);

    for (int i = 0; i < test.length; i++) {
        completionService.submit(new WorkSheet_1(i));
    }

    for (int i = 0; i < test.length; i++) {
        try {
            String result = completionService.take().get();
            System.out.println("Output Returned is : " + result);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // Compute the result
    }
于 2013-08-26T10:15:41.987 回答