一句话说透Java里面什么导致线程阻塞?

129 阅读2分钟

1. 排队等锁(像抢厕所)

  • 场景:多个线程抢同一把锁(比如 synchronized 或 ReentrantLock)。

  • 例子

    • 线程A进厕所(锁)了,线程B只能在门口堵着等,直到A出来。
    • 代码表现:线程在 synchronized 代码块外排队。

2. 睡觉(主动暂停)

  • 场景:线程自己调用 Thread.sleep(时间)

  • 例子

    • 线程说:“我先睡5秒,你们别叫我”,5秒后自动醒。
    • 注意:睡觉时不会释放锁,可能让其他线程干等。

3. 等别人通知(像等快递)

  • 场景:线程调用 object.wait(),释放锁并等待。

  • 例子

    • 线程A等快递(某个条件),说:“快递到了叫我(notify())”,然后去睡觉(阻塞)。
    • 线程B送快递后,喊一声“快递到了!”,线程A才继续干活。

4. 卡在IO操作(像等下载完成)

  • 场景:读写文件、网络请求等耗时操作。

  • 例子

    • 线程下载一部电影,必须等数据传完才能做其他事。
    • 优化:可以用异步IO(比如NIO),不等了,干别的去。

5. 等队友完成(像组队任务)

  • 场景:调用 thread.join(),等另一个线程结束。

  • 例子

    • 线程A说:“我等线程B干完活再继续”,于是A卡住,直到B结束。

6. 从未来取结果(像等外卖)

  • 场景:调用 Future.get() 拿异步任务结果。

  • 例子

    • 线程订了外卖(提交任务),然后一直等外卖送到(get()阻塞),中间啥也不干。

7. 队列满了或空了(像堵车)

  • 场景:用 BlockingQueue(如ArrayBlockingQueue)。

  • 例子

    • 队列像停车场:车满了不让进(线程阻塞),车空了不让出(线程也阻塞)。

总结:线程为什么卡住?

  • 等资源:锁、IO、数据、通知、队友结果。
  • 主动暂停:睡觉或故意等待。

如何避免无谓的卡住?

  • 用非阻塞IO(如NIO)。
  • 减少锁的竞争(比如减小锁粒度)。
  • 用线程池管理任务,别让线程无限等。
  • 尽量用异步编程(比如CompletableFuture)。

口诀
「线程阻塞像堵车,等锁等IO等通知
主动睡觉或等人,队列满空也卡住
优化代码少等待,异步非锁是出路!」