可调用执行顺序吗?

时间:2013-08-23 08:35:19

标签: java concurrency runnable java.util.concurrent callable

每当我运行我的程序实现可调用时,我都会以顺序形式获得输出。

喜欢,这是我的程序:

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 ...............

输出始终按顺序打印数组,而当我实现可运行输出时,按任意顺序输出:

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 ?

3 个答案:

答案 0 :(得分:4)

因为你在for循环中等待callable的结果:

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

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

答案 1 :(得分:4)

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

第一个,基于前面的答案,是将等待完成从等待任务的循环中移出。这样做允许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

&#34;运行xx&#34;消息或多或少按顺序开始,但很快就会出现故障。

答案 2 :(得分:2)

使用 CompletionService ,我们不需要在调用函数中打印Sysout(由@Patricia提供),使用CompletionService比使用Futures更有优势。

有关详细信息,请参阅java-concurrency-executors-and-thread-pools。 该网站说,

  

“使用未来的代码有点复杂。而且有一个缺点。如果   第一个任务需要很长时间来计算和所有其他任务   在第一个之前结束,当前线程无法计算结果   在第一个任务结束之前。此问题的解决方案是完成服务“

现在使用Sompletion Service的解决方案打印出所需的结果:

    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
    }
相关问题