一、同步异步 vs. 阻塞非阻塞
同步异步是针对于是否需要按顺序执行任务
阻塞非阻塞是针对于等待期间线程能否执行其他请求
二、同步 vs. 异步
同步指的是对于每个请求,必须等待上一个请求完成才可以进行下一请求。
异步指的是对于每个请求,不需要等待上一个请求完成就可以进行下一个请求,上一个请求完成后会通过回调机制通知。
三、阻塞 vs. 非阻塞
阻塞指的是在等待当前请求时,线程不能进行任何其他请求。
非阻塞指的是在等待当前请求时,线程也可以执行其他请求。
四、同步 vs. 阻塞
同步侧重于按顺序完成请求。
阻塞侧重于不能执行其他请求。
五、异步 vs. 非阻塞
异步侧重于不需要等待上一个请求的结果。
非阻塞侧重于等待请求期间,可以执行其他请求。
六、举例
场景:点餐
同步:你点了牛排,站在柜台前等待,牛排做好后你才能继续去点饮料。
异步:你点了牛排后,不需要等待,服务员做好了会叫你。
阻塞:你点了牛排,站在柜台前等待,不能做其他任何事情,直到牛排做好。
非阻塞:你点了牛排,然后去做其他事情,隔几分钟看看牛排是否做好。
七、实际开发中的例子
1. 同步阻塞
场景 1: 文件读取
使用 BufferedReader 或 FileReader 读取文件时,线程会在读取操作完成之前阻塞。这意味着在文件读取完成之前,无法进行其他操作。
场景 2: 数据库查询
使用 JDBC 进行数据库查询时,调用 executeQuery() 方法后,当前线程会被阻塞,直到数据库返回结果。此时,线程无法执行其他任务。
2. 同步非阻塞
场景 1: 轮询
某些情况下,程序可能需要定期检查某个条件是否满足(如文件是否生成、任务是否完成)。可以在一个循环中反复检查,并且在每次检查之间执行其他操作。这种方式是同步的,但不阻塞,因为每次检查之间可以进行其他操作。
场景 2: 定时任务
使用 ScheduledExecutorService 来执行定时任务。任务按照预定的时间间隔执行,而不是等待任务完成。这是一种同步方式,因为任务按顺序执行,但并不阻塞其他任务的执行。
3. 异步阻塞
场景 1: Future.get()
当使用 Future 进行异步任务时,调用 get() 方法会阻塞线程,直到异步操作完成并返回结果。这意味着任务本身是异步执行的,但在你获取结果时,线程会被阻塞。
场景 2: 回调中的阻塞操作
在异步调用中,如果回调函数内执行了阻塞操作(如 I/O 操作),这会导致尽管任务是异步的,但在处理结果时仍然会阻塞线程。
4. 异步非阻塞
场景 1: CompletableFuture
使用 CompletableFuture 的异步方法(如 supplyAsync)时,任务会异步执行,并且不会阻塞主线程。可以在任务完成后通过 thenApply 或 thenAccept 进行处理,而不影响主线程的运行。
场景 2: Reactive Programming (响应式编程)
在使用响应式框架(如 Project Reactor 或 RxJava)时,操作是完全异步和非阻塞的。例如,使用 Mono 或 Flux 来处理流式数据,这种方式下,数据的处理是异步的,并且不会阻塞调用线程。