线程基础-3 线程状态

一.线程包括哪些状态?

1.新建NEW:创建线程对象进入NEW状态。

2.可执行RUNNABLE:可执行又分为两种:
(1)就绪runnable:线程调用start()方法进入runnable。

(2)执行running:处于runnable的线程如果竞争到cpu使用权,则进入running执行;若失去cpu使用权,则重新回到runnable。

3.终止TERMINATED:线程执行完或是主线程的main()函数执行完,则线程终止,线程一旦终止则不能复生。

4.阻塞BLOCKED:处于RUNNABLE.running的线程如果没有竞争到锁(synchronized或lock),则进入BLOCKED阻塞。竞争到锁后再切换到RUNNABLE.runnable等待执行。

5.等待WAITING:处于RUNNABLE.running的线程如果调用wait()则进入WAITING等待,直到被其他线程调用notify()唤醒,再切换到RUNNABLE.runnable等待执行。

6.计时等待TIMED_WAITING:处于RUNNABLE.running的线程如果调用sleep()或wait(long)则进入计时等待状态,直到计时结束主动醒来,再切换到RUNNABLE.runnable等待执行。

注:线程的状态发生顺序是不可逆的:RUNNABLE.runnable-->RUNNABLE.running-->(BLOCKED、WAITING、TIMED_WAITING)-->RUNNABLE.runnable。

二.如何保证多个线程按先后顺序执行?

1.使用join()方法:thread1.join()表示执行到此代码的线程,会进入TIMED_WAITING等待,只有等到thread1线程执行完,当前线程才能醒来继续执行。

2.使用wait()+notify():后执行的线程调用wait()进入等待,先执行的线程执行完才调用notify()唤醒下一个线程。

三.notify()和notifyAll()的区别

1.notify()会随机唤醒一个因调用wait()或wait(long)进入等待的线程。

2.notifyAll()会唤醒所有因调用wait()或wait(long)进入等待的线程。

四.wait()和notify()的关系

1.获取锁:线程要使用wait()或notify()都必须先获取到锁。

(1)线程调用wait()进入WAITING,调用wait(long)进入TIMED_WAITING,都能被notify()唤醒。

(2)线程调用notify()会随机唤醒一个因调用wait()或wait(long)进入等待的线程。

(3)wait()和notify()通过对象锁关联:若thread1获得锁lock1,调用wait()进入等待;则其他线程只有同样获取锁lock1,才能调用notify()唤醒thread1,使用的是同一把锁。

2.释放锁:

(1)线程调用wait()或调用wait(long)进入等待后,会释放锁给其他线程使用,synchronized剩余代码不再执行。

(2)线程调用notify()唤醒其他线程后,不会释放锁,会继续执行完synchronized剩余代码。

五.wait()和sleep()的关系

1.方法归属不同

(1)wait()和wait(long)都是Object类的成员方法,每个对象都有。

(2)sleep()是Thread类独有的方法。

2.作用相同

(1)调用wait()进入WAITING,调用wait(long)或sleep()进入TIMED_WAITING。

(2)无论进入哪种状态,作用都是让cpu暂时放弃cpu使用权。

3.唤醒方式不同

(1)调用wait()进入等待的线程,只能被其他线程调用notify()或notifyAll()唤醒,若没有被唤醒则永久等待。

(2)调用wait(long)进入等待的线程,可以被其他线程调用notify()或notifyAll()唤醒,也可以等到计时结束主动醒来。

(3)调用sleep()进入等待的线程,只能等到计时结束主动醒来,或者通过interrupt()强行中断线程。

4.使用的条件不同

(1)线程要调用wait()或wait(long)都必须要先获取锁。

(2)线程要调用sleep()无需获取锁,直接使用即可。

5.对锁的处理不同

(1)线程调用wait()或wait(long)进入等待后,都会释放锁给其他线程使用。

(2)线程调用sleep()进入等待后,不会释放锁(抱着锁睡觉)。等计时结束主动醒来后,也会继续持有锁去切换到RUNNABLE.runnable等待执行。

六.如何停止一个正在运行的线程?

1.自定义变量充当退出标志,线程通过判断变量值来决定是否退出执行。为了防止编译器优化,该变量必须用volatile关键字修饰。

2.使用interrupt()中断线程。线程调用interrupt()可能会修改线程内部的中断标记,线程通过判断中断标记来决定是否退出执行。

(1)打断阻塞或等待(wait()、sleep()、join())的线程:阻塞或等待的线程调用interrupt()会直接抛出InterruptedException异常,中断执行。但该线程的中断标记不会被修改,因为还未修改就异常退出了。

(2)打断正常运行的线程:正在运行的线程调用interrupt()会修改线程内部的中断标记,但仅仅是修改了标记而已,线程会继续正常执行。若要达到中断效果还必须自己编写逻辑代码,通过判断线程的中断标记来让线程退出执行。

  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值