首先,我们知道 Runnable
接口是无返回值可执行代码的基础接口:
public interface Runnable {
void run();
}
自 Java 1.8 起该接口的匿名类可以简化为:
Runnable r = () -> { };
该 lambda 表达式很好理解,无参无返回值。
Thread
类是线程的抽象(它也实现了 Runnable
),我们可以直接通过创建 Thread
对象来操作线程:
new Thread(() -> { }).start();
但我们希望线程受到管理,所以我们使用 Executor
:
public interface Executor {
void execute(Runnable command);
}
主要是使用继承自 Executor
的 ExecutorService
类,它有以下常用的默认实现:
// 创建足够多的线程,并且循环使用,注意这里线程数没有上限
Executors.newCachedThreadPool();
// 创建固定数量的线程,未执行的任务进入等待队列
Executors.newFixThreadPool(threadNum);
// 创建至少某个数量的线程,以执行定时任务
Executors.newScheduledThreadPool(minThreadNum);
让我们使用一番:
ExecutorService executorService = Executors.newFixThreadPool(8);
for (int i = 0; i < 1000; i++) {
executorService.execute(() -> { });
}
executorService.shutdown(); // 不再接受新任务,已有任务仍会继续执行
try {
while (!executorService.isTerminated()) {
// 等待已有任务结束
executorService.awaitTermination(10, TimeUnit.SECONDS);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
很好用。
异常不能跨线程传播,所以只能在线程本地处理。我们可以通过给 ExecutorService
指定 ThreadFactory
,在创建线程时设置一些属性:
public interface ThreadFactory {
Thread newThread(Runnable r);
}
有 Thread.UncaughtExceptionHandler
接口:
public interface UncaughtExceptionHandler {
void uncaughtException(Thread t, Throwable e);
}
executorService = Executors.newSingleThreadExecutor(runnable -> {
Thread t = new Thread(runnable);
t.setUncaughtExceptionHandler((thread, exception) -> { });
return t;
});
通过 ExecutorService
的帮助,我们能够使用 Runnable
的有返回值版本 Callable
:
public interface Callable<V> {
V call() throws Exception;
}
public interface ExecutorService extends Executor {
<T> Future<T> submit(Callable<T> task);
}
Callable<String> callable = () -> { return ""; };
Future<String> future = executorService.submit(callable);
// 若目标任务未结束,则当前线程将等待直到目标任务返回或被中断
String result = future.get(); // is ""
// 对于 Runnable 任务,返回值为 null
Future<?> future1 = executorService.submit(() -> {});
Object result1 = future1.get(); // is null
Java 1.6 起提供 RunnableFuture
表示可以被 Thread
执行,还可以通过 Future
接口访问其结果。
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
RunnableFuture
有一个实现 FutureTask
:
Callable<String> task = () -> { return ""; };
FutureTask<String> ft = new FutureTask<String>(task);
// 通过以下任一方式执行
new Thread(ft).start();
executorService.submit(ft);
// 当前线程等待结果后返回
ft.get();
另外,可以通过以下方法获取当前 CPU 数量,以更好地使用线程池:
int cpuNums = Runtime.getRuntime().availableProcessors();