前言
最近在看一些Java15的并发、线程调度以及一些实现方案的东西,虽然很多东西还是 1.5 的,但还是很有收获。
一、线程与任务
Java中,要用线程来执行任务,线程可以说是任务的容器。没有线程的物理开启(start0),就不会有任务被执行。
如果看过 Thread 源码就能知道,Java 对线程的实现是非常封闭的,其机制来源于c的低级的p线程方法。源码中,通过 native 关键字,依托于JNI接口,调用其他语言来实现对底层的访问。
二、Java线程与任务的基础接口
在 concurrent 和 lang 包中,首先有几个基础接口需要了解:
Runnable
Callable
Future
Runnable
对于 任务或线程 而言,最基本和初级的功能就是运行,所以在 Java1.0 的时候,只有Runnable接口。Runnable 接口的规范也非常简单:
public interface Runnable {
public abstract void run();
}
没有返回值也没有异常抛出,就是简简单单的执行,将任务执行的代码实现在 run 函数里就成。如果需要获得任务执行结果,必须在函数中写 回调函数(callback function)。
实现 Runnable 接口,根据实际业务需求,抽象出具有个性化、简单化的、需要新线程执行的并行任务。
Thread 是实现 Runnable 的一个实现类,所以我个人理解,在 Java 的视角,线程实际上是一个特殊的任务。
Runnable 适合作为一个被实现的接口被任务类实现(因为 Thread 与 Executor 只能输入 Runnable)。
Callable
但如果仅仅是这样,可不满足我们对于任务管理的要求。线程执行任务所抛出的任务异常(注意不是线程异常,两者本质区别),以及返回的结果,我们想要更方便的获取。于是,在 Java1.5 中就有了 Callable 接口。
Callable 接口规范也不复杂:
public interface Callable {
V call() throws Exception;
}
和 Runnable 比起来,我们可以看到明显的改变。首先在线程执行任务的过程中,我们可以 catch 到任务抛出的异常。其次,我们可以拿到输入类型的返回值。
Callable 更适合作为一个任务内容被写到任务中,因为可以在 run 中轻松处理抛出异常。(这点在FutureTask 中会有所体现)
Future
在 Java1.5 中还提供了 Future 接口,来对任务进行更详细的管理。
public interface Future {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
//阻塞(等待)获取计算结果
V get() throws InterruptedException, ExecutionException;
//超时报错
V get(long timeout, TimeUnit unit)</