在开始解决上述问题之前我们来讨论下使用 Callbale 接口来创建线程.
@FunctionalInterface
public interface Callable<V> {
/**
* 返回一个任务的结果,或者抛出一个异常(如果不能计算结果)
*/
V call() throws Exception;
}
Callable 接口是一个函数式接口,其中 call()方法的返回值的类型就是 Callable 接口的泛型的类型.但是 Callable 接口怎么和线程扯上关系呢? FutureTask 类存在一个构造器:如下所示:
FutureTask(Callable < V > callable)
其中的参数正式 Callable 接口对象;FutureTask 类又是实现接口 RunnableFuture 接口:
public class FutureTask < V > implements RunnableFuture < V >
接着看:
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
最终的还是继承了 Runnable 接口和 Future 接口,为了说明关系,我们画出类图:
package com._thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThread implements Callable < String > {
/**
* 票的张数为50张,总共100个人买票
*/
private int ticket = 50; // 表示票的张数
@Override public String call() throws Exception {
for (int i = 0; i < 100; i++) {
if (ticket > 0) {
System.out.println("买票:ticket = " + this.ticket--);
}
}
return "票卖光了!";
}
public static void main(String[] args) throws InterruptedException,
ExecutionException {
// 创建Callable接口对象 在这里我创建了两个任务对象
Callable < String > callable1 = new CallableThread();
Callable < String > callable2 = new CallableThread();
// 将创建的callable任务对象存储在FutureTask对象中
FutureTask < String > task1 = new FutureTask < String > (callable1);
FutureTask < String > task2 = new FutureTask < String > (callable2);
// 启动线程执行任务
new Thread(task1).start();
new Thread(task2).start();
// 上述代码只是执行线程,callable接口是可以产生结果的,futuretask可以获取结果
// 调用get()方法可以阻止当前执行的线程获取结果
System.out.println("线程A的返回结果是:" + task1.get());
System.out.println("线程B的返回结果是:" + task2.get());
}
}
这是使用 callable 接口来创建线程的一种实现过程;好了现在让我们讨论 Java 异步编程吧!
上面的图可以说明我们的一个买书的过程,在 Java 中可以视这个操作为同步操作:
package com._thread;
public class SlowWorker {
public SlowWorker() {}
public void doWork() {
try {
System.out.println("==== 找书, 找书, 找书 ====== ");
Thread.sleep(2000);
System.out.println("==== OK! ======");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SlowWorker worker = new SlowWorker();
// 主线程模拟买书的人,doWork()方法模拟书店老板的行为!
System.out.println("老板,我要买书" + new java.util.Date());
worker.doWork();
System.out.println("... 老板在找书的过程中我可以干些事情吗!....");
System.out.println("书买到了" + new java.util.Date());
System.exit(0);
}
}
看运行结果:
老板,我要买书Sun Jan 21 01:49:35 CST 2018
==== 找书, 找书, 找书 ======
==== OK! ======
... 老板在找书的过程中我可以干些事情吗!....
书买到了Sun Jan 21 01:49:37 CST 2018
以上的操作确实是一种同步的操作;主线程运行开始后,调用 doWork() 方法,而 doWork() 方法需要休眠 2s. 但是主线程没有继续执行,而是等待了,大家是不是感觉这样做事很没有效率.换言之,如果你在书店买书,老板找一天,你会持续等待下去吗?
接下来我们谈谈 ExecutorService 这个接口,它可以表示线程池对象;当线程空闲时,它可以接受一个提交给 ExecutorService 的 callable 对象,当线程结束的时候,他会返回一个 Future.
package com._thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 异步编程
* @author gosaint
*
*/
public class AsynchronousWorker {
public AsynchronousWorker() {}
public void doWork() {
try {
System.out.println("==== 找书, 找书, 找书 ====== ");
Thread.sleep(2000);
System.out.println("==== OK! ======");
} catch(InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
SlowWorker worker = new SlowWorker();
// 主线程模拟买书的人,doWork()方法模拟书店老板的行为!
System.out.println("老板,我要买书" + new java.util.Date());
// 此时我们创建一个线程池,个数为3
ExecutorService service = Executors.newFixedThreadPool(3);
// 此时存在一个线程池对象,线程池对象提交任务,是一个callable接口
Future < String > future = service.submit(new Callable < String > () {@Override public String call() throws Exception {
new AsynchronousWorker().doWork();
return null;
}
});
System.out.println("... 老板在找书的过程中我可以干些事情吗!....");
System.out.println("做爱做的事情!");
try {
//调用此方法可以获取我们任务的执行结果,但是会阻止主线程的运行,直到得到一个结果
future.get();
} catch(InterruptedException e) {
e.printStackTrace();
} catch(ExecutionException e) {
e.printStackTrace();
}
System.out.println("书买到了" + new java.util.Date());
System.exit(0);
}
}
运行结果如下:
老板,我要买书Sun Jan 21 02:16:13 CST 2018
... 老板在找书的过程中我可以干些事情吗!....
做爱做的事情!
==== 找书, 找书, 找书 ======
==== OK! ======
书买到了Sun Jan 21 02:16:15 CST 2018
主线程开始运行,接着我们向 ExecutorService 提交了一个买书的任务,之后我们在干其他的事情.而最后呢,Future 对象从 ExecutorService 获取到了执行的结果.我们调用 get()方法获取到了执行的结果;倘若我们没有这个调用,那么还是一个并行计算,那么老板找书的结果不会立马给我们返回的;
来源: http://www.bubuko.com/infodetail-2469059.html