Callable对比Runnale接口来说,可以返回线程执行的结果:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14public static void main(String[] args) throws Exception { FutureTask future = new FutureTask(() -> { TimeUnit.SECONDS.sleep(10); return "hello"; }); new Thread(future).start(); // System.out.println(future.get()); 一直阻塞 // timeout会抛出异常 java.util.concurrent.TimeoutException System.out.println(future.get(9,TimeUnit.SECONDS)); }
其实Callable的功能就是通过Runnable接口来实现:
定义自己的Callable接口:
复制代码
1
2
3
4public interface MyCallable<T> { T call(); }
定义相应的Future类:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35public class MyFuture<T> implements Runnable { // volatile保证各线程内存的可见性,一定要加上 // 不然 get()方法可能会一直阻塞没有结果返回 private volatile Object result; private MyCallable<T> myCallable; public MyFuture(MyCallable<T> myCallable) { this.myCallable = myCallable; } @Override public void run() { // 调用call的方法 Object tempResult = myCallable.call(); // 将call方法返回的结果,给到result成员变量 result = tempResult; } // 阻塞方法,一直阻塞,直到拿到结果 public Object get(){ // 结果没有返回,一直阻塞(这里会一直耗用cpu的资源) while (result == null); return result; } // 限时阻塞,在一定时间内阻塞,timeout后返回null public Object get(long delta, TemporalUnit timeUnit){ LocalDateTime localDateTime = LocalDateTime.now().plus(delta,timeUnit); // 结果没有返回会阻塞delta时间,单位为timeUnit,如果result有值就返回, // 没有,那么达到预定时间会返回null,不会一直阻塞,你也可以抛出相应的异常 while (result == null && localDateTime.compareTo(LocalDateTime.now()) >= 0); return result; } }
测试:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class Test { public static void main(String[] args) { // 这里用到了java8的lamda表达式重写call方法 MyFuture<String> myFutrue = new MyFuture<>(()->{ try { // 模拟业务操作,睡3秒 TimeUnit.SECONDS.sleep(3); }catch (Exception e){ } return "hello"; }); new Thread(myFutrue).start(); // System.out.println(myFutrue.get()); 阻塞三秒后返回hello // System.out.println(myFutrue.get(2, ChronoUnit.SECONDS)); 阻塞两秒后,返回null System.out.println(myFutrue.get(4, ChronoUnit.SECONDS));// 阻塞3秒后返回hello } }
jdk里面的Callable实现可能更完善些,这些都是我随便想的,实现方式很多种,看你怎么实现。感觉这里用阻塞队列来实现应该也是可以的。就是call方法返回的值进入到队列种,get方法可以提供各种场景的返回值或者抛出异常,都可以用阻塞队列来完成。
最后
以上就是魁梧烧鹅最近收集整理的关于Callable的使用和自定义自己的Callable接口的全部内容,更多相关Callable内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复