java线程的状态+锁分析

在最开始贴出我的线程状态理解简图(没画出结束状态):


        相信很多小伙伴对这种图都有或多或少的印象,下面就来分析一下线程的整个可能出现的状态和状态变化出现的原因。我们都知道新建一个线程是很简单的,可以通过继承Thread或者实现Runnable/Callable接口来创建一个新的线程。在调用了start()方法之后该线程就进入了就绪状态,而且在就绪状态只能等待系统调度。在运行中的线程在碰到①t.join(),t.sleep(),或者是等待用户输入的过程就会进入阻塞状态,只有在②join前面的线程执行完或者sleep时间到了和系统给与了输入之后才能接除阻塞重新回到就绪状态,又或者是碰到了有synchonized关键字锁住的部分而且没有获取到锁的时候就会进入锁池状态知道获取到锁才回到就绪状态,当然这里也可以理解为进入了一个同步队列(这个稍后会再细讲)。又或者是碰到了Object的wait方法或者LockSupport.park()进入一个等待队列,当持有该对象的其他线程执行notify/notifyAll方法或者LockSupport.unpark()后会使其进入同步队列,当然这里还有一些超时的等待状态,跟不超时的类似,这里就不细说了。

        在前面的描述中一致有提到锁的概念,锁其实是JVM层提供的,每个对象都有一个monitor,当持有这个对象的monitor时我们说我们持有了这个对象的锁。synchonized关键字保证了同一个时刻只能有一个线程持有这把锁,它的具体实现是有monitorenter和monitorexit指令完成的,而且这两个指令一定是成对出现的。在线程的等待通知模型里面的运行过程如下图(t1为等待线程t2为唤醒线程):

这也是为什么我们说wait方法会释放锁的原因了。

补充:  Object的wait/notify和LockSupport的park/unpark区别:  Object的方法之间有严格的顺序控制,如果执行顺序出现变化就会得到不同的结果,但是park/unpark是针对线程作用,无论执行顺序是否变化,最终都会执行所有线程代码。

        

参考书籍:《java并发编程的艺术》


猜你喜欢

转载自blog.csdn.net/qq_36243399/article/details/79769598
今日推荐