Future

1. cancel(boolean mayInterruptIfRunning)和isCancelled()

 1 package Five_cancel_and_isCancelled;
 2 
 3 import java.util.concurrent.Callable;
 4 
 5 public class MyCallable implements Callable<String> {
 6 
 7     @Override
 8     public String call() throws Exception {
 9         // TODO Auto-generated method stub
10         System.out.println("begin :  " + System.currentTimeMillis());
11         Thread.sleep(2000);
12         System.out.println("end :  " + System.currentTimeMillis());
13         return "我的年龄是2000";
14     }
15 
16 }
 1 package Five_cancel_and_isCancelled;
 2 
 3 import java.util.concurrent.ExecutionException;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.LinkedBlockingDeque;
 6 import java.util.concurrent.ThreadPoolExecutor;
 7 import java.util.concurrent.TimeUnit;
 8 import java.util.concurrent.Future;
 9 
10 public class Test {
11 
12     public static void main(String[] args) throws InterruptedException, ExecutionException {
13 
14         MyCallable mc = new MyCallable();
15 
16         ExecutorService executor = new ThreadPoolExecutor(50, Integer.MAX_VALUE, 5, TimeUnit.SECONDS,
17                 new LinkedBlockingDeque<Runnable>());
18 
19         Future<String> f = executor.submit(mc);
20         System.out.println(f.get());
21         System.out.println(f.cancel(true) + "----------" + f.isCancelled());
22     }
23 }

运行结果:

分析:

  线程已经运行完毕,线程对象已经销毁,所以方法cancel(true)的返回值是false,代表发送中断线程的命令没有成功。因为这个命令中的参数的作用是:如果线程正在运行,则发送中断线程的命令。而线程已经运行结束了,所以没有满足这个命令执行的条件,所以命令没有执行成功。

 

修改:将这行代码注释掉

    //System.out.println(f.get());

运行结果:

true----------true

成功中断正在执行中的线程。

 分析:

  将这行注释掉,意味着没有取线程的返回值,那么线程就一直在call()方法中运行,直到接到了取返回值的命令,才会走到return,这时也意味着线程执行结束。

 

2. Future的缺点

  Future接口调用get()方法取得处理结果时是阻塞性的,就是说如果你调用了这个方法,它没有取到值,那么就会一直等在这儿,直到取到值为止,然后下面的程序才能接着运行。

  这样带来的问题就是:如果当前分支线程执行的任务很多,那么在主线程使用get()方法调用这个分支线程的返回值的程序会一直阻塞在这里,直到分支线程运行完毕并返回值,而在这个过程中,主线程get()方法后面的程序将无法运行,就一直在这里排队等待,这样会大大影响运行的效率,也就是说主线程不能保证首先获得的是最先完成任务的返回值。

 1 package Five_Future_Shortcoming;
 2 
 3 import java.util.concurrent.Callable;
 4 
 5 public class MyCallable implements Callable<String> {
 6 
 7     private String username;
 8     private long sleepValue;
 9 
10     public MyCallable(String username, long sleepValue) {
11         super();
12         this.username = username;
13         this.sleepValue = sleepValue;
14     }
15 
16     @Override
17     public String call() throws Exception {
18         // TODO Auto-generated method stub
19         System.out.println(username);
20         Thread.sleep(sleepValue);
21         return "return " + username;
22     }
23 
24 }
 1 package Five_Future_Shortcoming;
 2 
 3 import java.util.concurrent.LinkedBlockingDeque;
 4 import java.util.concurrent.ThreadPoolExecutor;
 5 import java.util.concurrent.TimeUnit;
 6 import java.util.concurrent.ExecutionException;
 7 import java.util.concurrent.Future;
 8 
 9 public class Test {
10 
11     public static void main(String[] args) throws InterruptedException, ExecutionException {
12 
13         MyCallable mc1 = new MyCallable("uer-1", 5000);
14         MyCallable mc2 = new MyCallable("uer-2", 4000);
15         MyCallable mc3 = new MyCallable("uer-3", 3000);
16         MyCallable mc4 = new MyCallable("uer-4", 2000);
17         MyCallable mc5 = new MyCallable("uer-5", 1000);
18 
19         ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
20                 new LinkedBlockingDeque<Runnable>());
21 
22         Future<String> f1 = executor.submit(mc1);
23         Future<String> f2 = executor.submit(mc2);
24         Future<String> f3 = executor.submit(mc3);
25         Future<String> f4 = executor.submit(mc4);
26         Future<String> f5 = executor.submit(mc5);
27 
28         System.out.println("Run first time : " + System.currentTimeMillis());
29 
30         System.out.println(f1.get() + "----" + System.currentTimeMillis());
31         System.out.println(f2.get() + "----" + System.currentTimeMillis());
32         System.out.println(f3.get() + "----" + System.currentTimeMillis());
33         System.out.println(f4.get() + "----" + System.currentTimeMillis());
34         System.out.println(f5.get() + "----" + System.currentTimeMillis());
35 
36         
37 
38     }
39 
40 }

运行结果:

分析:

  线程uer-1,睡眠的时间最长,为5秒钟,而在主线程中,第一个调用的就是uer-1的返回值,所以在主线程中,其他get()方法一直在等待uer-1的值get到之后才能运行,而uer-1的get()在等待uer-1线程执行完毕再返回值,所以就造成主线程里其它线程get的阻塞。

如果将get的顺序换过来,先get睡眠时间最短的

 1 package Five_Future_Shortcoming;
 2 
 3 import java.util.concurrent.LinkedBlockingDeque;
 4 import java.util.concurrent.ThreadPoolExecutor;
 5 import java.util.concurrent.TimeUnit;
 6 import java.util.concurrent.ExecutionException;
 7 import java.util.concurrent.Future;
 8 
 9 public class Test {
10 
11     public static void main(String[] args) throws InterruptedException, ExecutionException {
12 
13         MyCallable mc1 = new MyCallable("uer-1", 5000);
14         MyCallable mc2 = new MyCallable("uer-2", 4000);
15         MyCallable mc3 = new MyCallable("uer-3", 3000);
16         MyCallable mc4 = new MyCallable("uer-4", 2000);
17         MyCallable mc5 = new MyCallable("uer-5", 1000);
18 
19         ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
20                 new LinkedBlockingDeque<Runnable>());
21 
22         Future<String> f1 = executor.submit(mc1);
23         Future<String> f2 = executor.submit(mc2);
24         Future<String> f3 = executor.submit(mc3);
25         Future<String> f4 = executor.submit(mc4);
26         Future<String> f5 = executor.submit(mc5);
27 
28         System.out.println("Run first time : " + System.currentTimeMillis());
29 
30 
31 
32         System.out.println(f5.get() + "----" + System.currentTimeMillis());
33         System.out.println(f4.get() + "----" + System.currentTimeMillis());
34         System.out.println(f3.get() + "----" + System.currentTimeMillis());
35         System.out.println(f2.get() + "----" + System.currentTimeMillis());
36         System.out.println(f1.get() + "----" + System.currentTimeMillis());
37 
38     }
39 
40 }

 

 

  注:使用CompletionService接口可以解决这个问题

 1 package Five_Future_Shortcoming;
 2 
 3 import java.util.concurrent.LinkedBlockingDeque;
 4 import java.util.concurrent.ThreadPoolExecutor;
 5 import java.util.concurrent.TimeUnit;
 6 import java.util.concurrent.CompletionService;
 7 import java.util.concurrent.ExecutionException;
 8 import java.util.concurrent.ExecutorCompletionService;
 9 
10 public class Test1 {
11 
12     public static void main(String[] args) throws InterruptedException, ExecutionException {
13 
14         MyCallable mc1 = new MyCallable("uer-1", 5000);
15         MyCallable mc2 = new MyCallable("uer-2", 4000);
16         MyCallable mc3 = new MyCallable("uer-3", 3000);
17         MyCallable mc4 = new MyCallable("uer-4", 2000);
18         MyCallable mc5 = new MyCallable("uer-5", 1000);
19 
20         ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
21                 new LinkedBlockingDeque<Runnable>());
22 
23         CompletionService csRef = new ExecutorCompletionService(executor);
24 
25         csRef.submit(mc1);
26         csRef.submit(mc2);
27         csRef.submit(mc3);
28         csRef.submit(mc4);
29         csRef.submit(mc5);
30 
31         System.out.println("Run first time : " + System.currentTimeMillis());
32 
33         System.out.println(csRef.take().get() + "----" + System.currentTimeMillis());
34         System.out.println(csRef.take().get() + "----" + System.currentTimeMillis());
35         System.out.println(csRef.take().get() + "----" + System.currentTimeMillis());
36         System.out.println(csRef.take().get() + "----" + System.currentTimeMillis());
37         System.out.println(csRef.take().get() + "----" + System.currentTimeMillis());
38 
39     }
40 
41 }

运行结果:

可以看到,哪个线程先执行完,哪个任务的返回值就先打印。解决了Future阻塞的特性。

posted @ 2021-04-03 11:31  L1998  阅读(87)  评论(0)    收藏  举报