首先我们先来回顾下创建线程池:
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque());
线程池的submit可以提交一个Callable任务,Future的get方法可以获取到Callable的call()方法的返回值,看下一小节:
Callable接收一个泛型,我们可以根据项目需要自由传入泛型,这里我们以最简单的String为例。
首先我们创建一个类:TestCallable
public class TestCallable implements Callable<String> {
private String name;
public TestCallable(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
return getName();
}
private String getName() {
try {
//模拟耗时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return name + "123";
}
}
注解里面写的很详细,这里注意下模拟的耗时操作,睡眠了1秒,目的是稍后我们在执行线程池任务的时候,为了验证get()方法有阻塞作用。
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque());
TestCallable testCallable = new TestCallable("张三");
Future future = executor.submit(testCallable);
try {
//返回call()方法的返回值,有阻塞作用
String name = future.get();
System.out.println("name = " + name);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//为了证明get()方法有阻塞作用,在这里输出一条语句
System.out.println("执行了,看看我在get()方法前面还是后面执行~~~");
}
接下来看下log:
12-28 10:00:34.410 11613-11613/lbx.myapplication I/System.out: name = 张三123
12-28 10:00:34.410 11613-11613/lbx.myapplication I/System.out: 执行了,看看我在get()方法前面还是后面执行~~~
通过log我们可以发现,get()方法确实用阻塞效果,当任务执行完后,释放阻塞,然后返回任务的处理结果。
线程池中有一个方法:
Future<Result> future = executor.submit(Runnable, result);
第二个参数是执行结果的返回值。这么说可能有些抽象,我们来举个小栗子:
创建一个Bean类,作为Result的基类:
public class TestBean {
public String name;
}
接下来创建一个Runnable任务:
public class TestRunnable implements Runnable {
private TestBean testBean;
public TestRunnable(TestBean testBean) {
this.testBean = testBean;
}
@Override
public void run() {
testBean.name = "张三";
System.out.println("TestRunnable");
}
}
我们把TestBean 传进来,这个Runnable的任务就是,把TestBean 的name属性赋值。
接下来:
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingDeque());
TestBean testBean = new TestBean();
Future future = executor.submit(new TestRunnable(testBean), testBean);
try {
//注意有阻塞效果
TestBean bean = future.get();
System.out.println("bean = " + bean.name);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
log:
12-28 13:12:54.919 4321-4466/lbx.myapplication I/System.out: TestRunnable
12-28 13:12:54.919 4321-4321/lbx.myapplication I/System.out: bean = 张三
我们发现 通过get()方法或得到的返回结果,是赋值以后的TestBean 。
//没有阻塞作用,future任务是否完成
future.isDone();
//取消正在进行的任务,可以配合Thread.currentThread().isInterrupted()和InterruptedException在Callable的call方法里使用
future.cancel(true);
//是否取消成功
future.isCancelled();
//在n秒内获取,超过时长阻塞效果消失并抛出异常
future.get(n, TimeUnit.SECONDS);