Thread理一理
可恶,阅读aqs的时候发现对java多线程各种操作不敏感,进度就很憋屈,这里给自己理一下。
线程状态
- 初始态
- 就绪态
- 运行态
- 等待态
- 计时等待态
- 阻塞态
- 终止态
状态转换
- 初始态:也就是线程刚创建的状态,对应java就是线程还没有start之前的状态,此状态在线程状态转换中存在感较低,只是个入口。
- 就绪态:这就是已经开始执行的线程的初始状态了,在等待cpu时间片轮转到就绪态的线程,那么就会转换到运行态。
- 运行态:字面意思,这就是冲冲冲状态。
- 等待态:也是字面意思,线程等待了,需要被别的线程显示的唤醒,进入就绪态。
- 计时等待态:和等待态类似,不过不只是可以通过别的线程显示的唤醒,而是可以当设置的等待时间结束后,重新成为就绪态。
- 阻塞态:进入同步代码块,或者io阻塞,同步代码块就是synchorized重量级锁锁住的代码快,io阻塞就是当用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,简单来说就是咱调用read()方法会把线程阻塞在这里,等待用户输入。
终止态:线程的方法执行结束了就是变成终止态了,一旦被终止就不能复生了。
copy一张图:
挺清晰的哈:
- 初始态:start()方法,让线程进入就绪态。
- 就绪态:没有方法帮助它进行状态切换,只能等待时间片的降临而转换成运行态。
- 运行态:
运行结束或者异常中断会变成终止态。
调用wait()、join()、park()会让运行态线程转换为等待态,等待被唤醒。
调用wait(milies)、join(milies)、sleep(milies)、parkNanos()会让线程进入计时等待态。
遇到同步代码块或者io,进入阻塞态。 - 等待态:处于等待态的线程被调用notify()/notifyAll()、unpark()或者run()结束了,会被唤醒进入就绪态。
- 计时等待态:处于计时等待态相比等待态就多一个超时释放。
- 阻塞态:等待同步代码块释放或者io结束就完事。
这里单独托出来说一个部分,那就是中断对线程的影响。
中断
中断我的理解就是java对线程停止的一个操作,也是现在jdk推荐的唯一停止线程的操作。
它实际的运行没有它的名字霸气,也就是说不是说中断就直接中断线程,需要这样来理解:
每个线程都会拥有一个中断标志位,默认是false,可以通过调用方法来将线程的中断标记位置为true。
当线程做竞争锁、运行态等状态下,线程是不可中断的,中断标记不会对线程产生影响(除非显示的进行判断停止)。
但是当线程处于等待态、超时等待态时,线程会定时的判断中断标记位是否标记中断,如果中断标记位是true,那么线程会终止。
可以通过以下三种方式来判断中断:
- isInterrupted()
此方法只会读取线程的中断标志位,并不会重置。 - interrupted()
此方法读取线程的中断标志位,并会重置。 - throw InterruptException
抛出该异常的同时,会重置中断标志位。
可以通过线程的interrupt()方法来设置中断标志位true。
原本java是提供了一个stop()方法来终止线程的,很霸道的直接停止线程,但是由于它手段的暴力,可能会造成一些对象的异常赋值,就被弃用了。