只有runnable到running时才会占用cpu时间片,其他都会出让cpu时间片。线程的资源有不少,但应该包含CPU资源和锁资源这两类。sleep(long mills):让出CPU资源,但是不会释放锁资源。wait():让出CPU资源和锁资源。
锁是用来线程同步的,sleep(long mills)虽然让出了CPU,但是不会让出锁,其他线程可以利用CPU时间片了,但如果其他线程要获取sleep(long mills)拥有的锁才能执行,则会因为无法获取锁而不能执行,继续等待。但是那些没有和sleep(long mills)竞争锁的线程,一旦得到CPU时间片即可运行了。
阻塞唤醒过程
阻塞:
这三个方法的调用都会使当前线程阻塞。该线程将会被放置到对该Object的请求等待队列中,然后让出当前对Object所拥有的所有的同步请求。线程会一直暂停所有线程调度,直到下面其中一种情况发生:
① 其他线程调用了该Object的notify方法,而该线程刚好是那个被唤醒的线程;
② 其他线程调用了该Object的notifyAll方法;
唤醒:
线程将会从等待队列中移除,重新成为可调度线程。它会与其他线程以常规的方式竞争对象同步请求。一旦它重新获得对象的同步请求,所有之前的请求状态都会恢复,也就是线程调用wait的地方的状态。线程将会在之前调用wait的地方继续运行下去。
为什么要出现在同步代码块中:
由于wait()属于Object方法,调用之后会强制释放当前对象锁,所以在wait() 调用时必须拿到当前对象的监视器monitor对象。因此,wait()方法在同步方法/代码块中调用。
stop() 和 interrupt() 方法的区别
stop() 方法会立即杀死线程,如果线程持有 ReentrantLock 锁,是不会调用 ReentrantLock 的 unlock() 去释放锁的,因此其他线程也就没有机会获得 ReentrantLock 锁,这是很危险的。类似的还有 suspend() 方法和 resume() 方法。
interrupt() 方法仅仅是通知线程中断,被通知的线程有机会执行一些后续的操作,同时也可以无视这个通知。收到通知的方式有两种:一种是异常,另一种是主动检测。
当线程 A 处于 WAITING、TIMED_WAITING 状态时,其他线程调用 A.interrupt() 方法,会使线程 A 转到 RUNNABLE 状态,同时线程 A 的代码会触发 InterruptedException 异常。
当线程 A 处于 RUNNABLE 状态时,并且阻塞在 Java.nio.channels.InterruptibleChannel 上时,如果其他线程调用 A.interrupt() ,A 会触发 ClosedByInterruptException 异常;如果阻塞在 Selector 上,会立即返回。
如果线程处于 RUNNABLE 状态,并且没有阻塞在某个 I/O 操作上,中断就要依赖线程主动检测中断状态了,通过调用 isInterrupted() 方法。
为什么局部变量是线程安全的
![[attachments/ea4dbf178106fba9eceea9900ca1a11d_MD5.png]]
每个方法在调用栈里都有自己的独立空间,称为栈帧。
每个栈帧里都有对应方法需要的参数和返回地址。当调用方法时,会创建新的栈帧,并压入调用栈;当方法返回时,对应的栈帧就会被自动弹出。也就是说栈帧和方法是同生共死的。方法的调用是利用栈结构解决的
![[attachments/8277df6b572cb542b40b621bc0dd3704_MD5.png]]
局部变量放到了调用栈里
wait yield sleep join
sleep **,释放cpu资源,不释放锁资源,如果线程进入sleep的话,释放cpu资源,如果外层包有Synchronize,那么此锁并没有释放掉。
wait,释放cpu资源,也释放锁资源, 一般用于锁机制中 肯定是要释放掉锁的,因为notify并不会立即调起此线程,因此cpu是不会为其分配时间片的,也就是说wait 线程进入等待池,cpu不分时间片给它,锁释放掉。
(wait用于锁机制,sleep不是,这就是为啥sleep不释放锁,wait释放锁的原因,sleep是线程的方法,跟锁没半毛钱关系,wait,notify,notifyall 都是Object对象的方法,是一起使用的,用于锁机制)
yield:让出CPU调度,Thread类的方法,类似sleep。只是不能由用户指定暂停多长时间 ,并且yield()方法只能让同优先级的线程有执行的机会。 yield()只是使当前线程重新回到可执行状态,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。调用yield方法只是一个建议,告诉线程调度器我的工作已经做的差不多了,可以让别的相同优先级的线程使用CPU了,没有任何机制保证采纳。
join:一种特殊的wait,当前运行线程调用另一个线程的join方法,当前线程进入阻塞状态直到另一个线程运行结束等待该线程终止。 注意该方法也需要捕捉异常。
参考
https://mp.weixin.qq.com/s/IVgGXQKU1QiT1ToN2wXHJg
- 复现Java线程生命周期 (@2024-02-13)