目录
3.6.2. park-unpark与wait-notify的区别
3.5. wait-notify机制
3.5.1. wait-notify介绍
wait方法和notify方法都是Object类的方法
object.wait()
:让当前获取锁的线程进入waiting状态,并进入waitlist队列object.wait(long n)
:让当前获取锁的线程进入waiting状态,并进入waitlist队列,等待n秒后自动唤醒object.notify()
:在waitlist队列中挑一个线程唤醒object.notifyAll()
:唤醒所有在waitlist队列中的线程
它们都是之间协作的手段,只有拥有对象锁的线程才能调用这些方法,否则会出现IllegalMonitorStateException异常
3.5.2. 原理
wait调用条件:owner线程获取了该对象的锁,但是发现自己条件不满足使用共享资源的条件/竞态条件存在时,会调用wait方法进入waiting状态并进入Monitor对象的waitlist中,释放对象锁
处于waiting状态中的线程可以被notify/notifyAll方法唤醒,唤醒之后不一定马上可以获取锁,仍需进入EntryList竞争锁
3.5.3. wait和sleep的区别
- 从属层面:sleep是Thread方法,wait是Object方法
- 使用层面:sleep不需要强制和synchronized使用,wait方法需要和synchronized使用
- 作用效果:sleep在睡眠时不会释放对象锁,wait在等到时会释放对象锁
3.5.4. join原理
join是使用了保护性暂停模式,并在此基础上扩展了超时等待
- 使用经历时间和这一轮应该等待的时间来确保等待时间不超过指定的时间
- 当条件不满足但是又经历一次notify,还是进入while循环,这时等待的时间可能会超过指定时间
public final synchronized void join(long millis)throws InterruptedException { //开始时间 long base = System.currentTimeMillis(); //经历时间 long now = 0; if (millis < 0) { //如果指定等待时间等于0则抛出异常 throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { //如果指定等待时间为正数 while (isAlive()) { //求出这一轮循环应该等待的时间 long delay = millis - now; if (delay <= 0) { //等待时间小于0直接退出循环 break; } //等待这一轮应该等待的时间,防止唤醒后的条件不满足再次等待原有时间导致超时 wait(delay); //求出经历的时间 now = System.currentTimeMillis() - base; } } }
3.6. park-unpark机制
3.6.1. park-unpark介绍
park方法和unpark方法是LockSupport类中的方法
LockSupport.park()
:用于暂停当前的线程LockSupport.unpark(thread)
:用于恢复某个线程,既可以在park()
之前调用也可以在之后调用
3.6.2. park-unpark与wait-notify的区别
wait-notify
是Object类的方法,必须结合加锁对象使用,park-unpark
没有限制notify
随机唤醒一个线程,notifyAll
唤醒全部线程,park(thread)
唤醒指定的线程notify
必须用在wait
之后,unpark
既可以用在park
之前,也可以用在park
之后
3.6.3. park-unpark原理
每个线程都会关联一个Parker(jvm层面)对象,有一个当前线程许可计数permit
LockSupport.park()
:调用park时,会先检查permit,如果大于0则将permit-1后返回,线程继续执行.如果小于0则线程进入阻塞状态,等待被唤醒或打断LockSupport.unpark(thread)
:调用unpark时,将permit+1,
3.7. 线程状态转换
编辑
以下是线程各个状态之间的转换以及调用的方法
NEW-->RUNNABLE
thread.start()
:thread线程的状态NEW-->RUNNABLE
RUNNABLE<-->WAITING
- 线程进入
synchronized(obj)
代码块,获取对象锁之后
obj.wait()
:当前线程的状态RUNNABLE-->WAITING
obj.notify() 或 obj.notifyAll() 或 obj.interrupt()
:- 竞争锁成功,当前线程的状态
WAITING-->RUNNABLE
- 竞争锁失败,当前线程的状态
WAITING-->BLOCKED
thread.join()
:当前线程中调用线程thread的join方法会在thread线程对象上的监视器等待,当前线程的状态RUNNABLE-->WAITING
thread线程运行结束 或 被打断
:当前线程的状态WAITING-->RUNNABLE
LockSupport.park()
: 当前线程的状态RUNNABLE-->WAITING
LockSupport.unpark(thread)
:指定线程的状态WAITING-->RUNNABLE
RUNNABLE<-->TIMED_WAITING
- 线程进入
synchronized(obj)
代码块,获取对象锁之后
obj.wait(long n)
:当前线程的状态RUNNABLE-->TIMED_WAITING
当前线程等待n秒 或 被唤醒和打断
:- 竞争锁成功,当前线程的状态
TIMED_WAITING-->RUNNABLE
- 竞争锁失败,当前线程的状态
TIMED_WAITING-->BLOCKED
Thread.sleep(long n)
:当前线程的状态RUNNABLE-->TIMED_WAITING
当前线程等待n秒
:竞争锁成功,当前线程的状态TIMED_WAITING-->RUNNABLE
LockSupport.parkNanos(long nanos) 或 LockSupport.parkUnitl(long millis)
:当前线程状态:RUNNABLE-->TIMED_WAITING
LockSupport.unpark(thread) 或 被打断 或 等待超时
:目标线程状态TIMED_WAITING-->RUNNABLE
RUNNABLE<-->BLOCKED
- thread线程使用synchronized(obj)获取对象锁竞争失败,thread线程状态
RUNNABLE-->BLOCKED
- 持有锁的线程的同步代码块执行完毕,唤醒阻塞中的线程竞争锁
- 竞争成功
BLOCKED-->RUNNABLE
- 竞争失败
BLOCKED
RUNNABLE<-->TERMINATED
- 当前线程所有代码运行完毕
RUNNABLE-->TERMINATED