ref:
多进程 vs 多线程
- 多线程优势:创建线程开销小、通信快(读写同一个变量)
- 多进程优势:稳定,一个进程崩溃不会影响其他进程,一个线程崩溃会导致整个进程崩溃
一个java程序就是一个JVM进程,这个进程会用一个主线程执行 main()方法,在main()方法内部,可以自定义启动多个线程,此外 JVM 进程还启动着负责 GC 等工作的线程。所以说,java 支持多线程很自然,Java 的多任务一般是指多线程实现多任务。多线程是最基本的并发模型,在读写网络、数据库、web开发等都很常用。
Thread 和 Runnable
java 1 开始就有 Thread 可以用来实现异步,但仅仅依赖这个类来写大型并发比较困难
Runnable task = () -> {
String threadName = Thread.currentThread().getName();
System.out.println("Hello " + threadName);
}; // 等号右边也可以直接卸载new Thread()里面。
task.run(); // 在主 thread 中执行
Thread t = new Thread(task); // 实例化一个线程
t.start(); // 启动线程,新线程会执行run()方法
// t.join(); // 如果有这一句,则主线程会等 t 执行结束再执行,t.join();就是给等待时间加个上限
System.out.println("Done!"); // 这里还是主 thread,它和新起的 thread 不见得谁先谁后结束
java 线程的状态有以下几种:
- New:新创建的线程,尚未执行;
- Runnable:运行中的线程,正在执行
run()方法的Java代码; - Blocked:运行中的线程,因为某些操作被阻塞而挂起;
- Waiting:运行中的线程,因为某些操作在等待中;
- Timed Waiting:运行中的线程,因为执行
sleep()方法正在计时等待; - Terminated:线程已终止,因为
run()方法执行完毕。
用一个状态转移图表示如下:
┌─────────────┐
│ New │
└─────────────┘
│
▼
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
┌─────────────┐ ┌─────────────┐
││ Runnable │ │ Blocked ││
└─────────────┘ └─────────────┘
│┌─────────────┐ ┌─────────────┐│
│ Waiting │ │Timed Waiting│
│└─────────────┘ └─────────────┘│
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
│
▼
┌─────────────┐
│ Terminated │
└─────────────┘
Executor Services 和 Future
并发API在2004年Java5发布的时候才被引入。这些API位于java.util.concurrent包下。
java.util.concurrent包包含了很多处理并发编程的类,这些类自推出后就在后续java版本中不断增强。Java8 还提供了新的类和方法。
并发API中最重要的一部分是 executor services。
ExecutorService.submit()方法,可以看到,它返回了一个Future类型,一个Future类型的实例代表一个未来能获取结果的对象。
CompletableFuture
廖雪峰
java 8 引入,对 Future 做了改进,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法。而不用像 Future那样调用 get()去阻塞地获取结果。
- Future.get() 就是阻塞调用,在线程获取结果之前get方法会一直阻塞。
- Future提供了一个isDone方法,可以在程序中轮询这个方法查询执行结果。
阻塞的方式和异步编程的设计理念相违背,而轮询的方式会耗费无谓的CPU资源。因此,JDK8设计出CompletableFuture。CompletableFuture提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方。
写法上,CompletableFuture 可以不主动创建线程池(写 ExecutorService)。
xxx():表示该方法将继续在已有的线程中执行;xxxAsync():表示将异步在线程池中执行
CompletableFuture可以指定异步处理流程:
thenAccept()处理正常结果;exceptional()处理异常结果;thenApplyAsync()用于串行化另一个CompletableFuture;anyOf()和allOf()用于并行化多个CompletableFuture。