1. 排队等锁(像抢厕所)
-
场景:多个线程抢同一把锁(比如
synchronized或ReentrantLock)。 -
例子:
- 线程A进厕所(锁)了,线程B只能在门口堵着等,直到A出来。
- 代码表现:线程在
synchronized代码块外排队。
2. 睡觉(主动暂停)
-
场景:线程自己调用
Thread.sleep(时间)。 -
例子:
- 线程说:“我先睡5秒,你们别叫我”,5秒后自动醒。
- 注意:睡觉时不会释放锁,可能让其他线程干等。
3. 等别人通知(像等快递)
-
场景:线程调用
object.wait(),释放锁并等待。 -
例子:
- 线程A等快递(某个条件),说:“快递到了叫我(
notify())”,然后去睡觉(阻塞)。 - 线程B送快递后,喊一声“快递到了!”,线程A才继续干活。
- 线程A等快递(某个条件),说:“快递到了叫我(
4. 卡在IO操作(像等下载完成)
-
场景:读写文件、网络请求等耗时操作。
-
例子:
- 线程下载一部电影,必须等数据传完才能做其他事。
- 优化:可以用异步IO(比如NIO),不等了,干别的去。
5. 等队友完成(像组队任务)
-
场景:调用
thread.join(),等另一个线程结束。 -
例子:
- 线程A说:“我等线程B干完活再继续”,于是A卡住,直到B结束。
6. 从未来取结果(像等外卖)
-
场景:调用
Future.get()拿异步任务结果。 -
例子:
- 线程订了外卖(提交任务),然后一直等外卖送到(
get()阻塞),中间啥也不干。
- 线程订了外卖(提交任务),然后一直等外卖送到(
7. 队列满了或空了(像堵车)
-
场景:用
BlockingQueue(如ArrayBlockingQueue)。 -
例子:
- 队列像停车场:车满了不让进(线程阻塞),车空了不让出(线程也阻塞)。
总结:线程为什么卡住?
- 等资源:锁、IO、数据、通知、队友结果。
- 主动暂停:睡觉或故意等待。
如何避免无谓的卡住?
- 用非阻塞IO(如NIO)。
- 减少锁的竞争(比如减小锁粒度)。
- 用线程池管理任务,别让线程无限等。
- 尽量用异步编程(比如CompletableFuture)。
口诀:
「线程阻塞像堵车,等锁等IO等通知
主动睡觉或等人,队列满空也卡住
优化代码少等待,异步非锁是出路!」