Java能使得线程阻塞的基础工具(其余能阻塞线程的方法都是基于它们的)有4种:
- synchronized关键字
控制对资源的同步访问,如果另一个线程已经持有了对象锁,那么尝试获取锁的线程将被阻塞,并且线程的状态会变为BLOCKED。 - Object.wait:
当线程调用wait()方法时,它必须持有该对象的锁。wait()会释放锁。这时线程的状态将变为WAITING(或在使用wait(long timeout)时变为TIMED_WAITING)。线程会保持等待状态直到被notify()或notifyAll()唤醒,或是等待超时。 - LockSupport.park和LockSupport.parkNanos:
LockSupport.park()和相关方法使线程进入阻塞状态,直到它接收到一个“许可”(从其他线程调用unpark()),或者有其他中断。在使用LockSupport阻塞时,线程的状态是WAITING或TIMED_WAITING(如果使用了parkNanos()或parkUntil()方法的话)。 - Thread.sleep(long millis)
其中Thread.sleep(long millis)是打酱油的,不涉及线程的同步或协作,一般只用于示例、教学代码或测试代码中。所以我们主要关注另外3种即可。
为啥有了Object.wait()还需要LockSupport.park()呢?
因为Object.wait()只能在synchronized同步块中使用,而LockSupport.park()则更灵活,没有必须在同步块中使用的限制条件。
Lock、Condition、BlockingQueue、Semaphore、CountDownLatch、CyclicBarrier等都是使用LockSupport.park()来阻塞线程。
synchronized、Object.wait()和Lock、Condition.await()这两套怎么选?
阻塞在一个条件上,选synchronized、Object.wait(),代码写起来更简洁。
阻塞在多个条件上,没得选,必须用Lock、Condition.await()。