Java提高——多线程(四)线程通信、线程中断、优先级和守护线程

比眉伴天荒 2022-05-24 23:59 403阅读 0赞
线程通信——等待&唤醒

关于Object类提供的wait、notify、notifyAll三个方法:

wait():让当前线程放弃CPU、共享资源,处于等待(阻塞)状态,直到其他线程调用该同步监视器的notify(),notifyAll()方法来唤醒该线程,进入就绪状态。wait()会释放对当前线程的同步监视器的锁定。

—>无时间参数的wait:一直等到,直到其他线程通知唤醒

—>带时间参数的wait:等待指定时间后自动唤醒。

notify():唤醒在此同步监视器上等待的单个线程。若监视器上有很多个线程等待,则任意唤醒一个。

notifyAll():唤醒在此同步监视器上等待的所有线程。

Java.lang.Object提供的这三个方法只有在synchronized方法或代码块中才能使用,否则会报出java.lang.IllegalMonitorStateException异常

wait&notify示例:

  1. class Thread2 extends Thread{
  2. public Thread2(String name) {
  3. super(name);
  4. }
  5. @Override
  6. public void run(){
  7. synchronized (this) {
  8. System.out.println(Thread.currentThread().getName()+" call notify()");
  9. //唤醒当前的wait线程
  10. notify();
  11. }
  12. }
  13. }
  14. public class WaitTest {
  15. public static void main(String[] args) throws InterruptedException {
  16. Thread2 t = new Thread2("t2");
  17. synchronized (t) {
  18. //启动线程
  19. t.start();
  20. //让线程等待
  21. System.out.println("wait");
  22. t.wait();
  23. }
  24. }
  25. }

主线程main通过实例化获取线程t,随后通过synchronized(t)获取t对象的同步锁,之后调用start方法启动线程t。

主线程main通过执行t.wait()释放t的同步锁,进入了“等待(阻塞)状态”,等待t对象通过notify唤醒“当前对象上等待的线程”,也就是主线程。

70

wait和notify之间依赖于同步锁,而同步锁是对象持有的,因此这几个方法属于Object。

线程中断

中断方式:

—>终止处于“阻塞状态”的线程

当线程调用了yield、join、sleep等方法进入阻塞状态,若此时调用线程的interrupt()方法,将线程中断标记设置为true,处于阻塞状态,中断标记将被清除同时产生一个IntertuptedException异常,将异常放在适合的位置将会终止线程。

  1. @Override
  2. public void run() {
  3. try {
  4. while (true){
  5. //to-do
  6. }
  7. }catch(InterruptedException ie){
  8. // 产生InterruptedException异常,退出while循环,线程终止
  9. }
  10. }

—>终止处于“运行状态”的线程

1)通过“中断标记”中断线程

  1. @Override
  2. public void run() {
  3. while (!isInterruped()){
  4. //.......
  5. }
  6. }

isInterrupted是判断线程中的中断标记是否为true

2)通过“额外标记”中断线程

  1. private volatile boolean flag = true;
  2. @Override
  3. public void run() {
  4. while (flag){
  5. //.......
  6. }
  7. }
优先级

Java中的优先级范围是1-10:

MAX_PRIORITY:10

MIN_PRIORITY:1

NOR_PRIORITY:5(默认)

可以通过setPriority()改变线程的优先级,高优先级的线程将会获得更多执行的机会。

守护线程

Java的线程分为两种:用户线程和守护线程(后台线程),可以用isDaemon()方法来区别:如果返回false则为用户线程,否则为守护线程,JVM的垃圾回收线程就是典型的守护线程(后台线程)

后台线程的特征:如果前台线程都死亡,后台线程会自动死亡。

可以用setDaemon(true)将指定线程设定为后台线程。

  1. class Daemon extends Thread{
  2. //后台线程的设定与普通线程并没有任何区别
  3. @Override
  4. public void run() {
  5. for (int i = 0; i < 10 ; i++) {
  6. System.out.print(Thread.currentThread().getName()+"-"+i);
  7. }
  8. }
  9. }
  10. public class Test {
  11. public static void main(String[] args) {
  12. Daemon d = new Daemon();
  13. //将线程设置为守护线程
  14. d.setDaemon(true);
  15. //启动线程
  16. d.start();
  17. for (int i = 0; i < 10 ; i++) {
  18. System.out.println(Thread.currentThread().getName()+" "+i+" ");
  19. }
  20. //线程执行到此,前台线程(main)执行结束
  21. //后台线程也跟着结束
  22. }
  23. }

主线程默认为前台线程。前台线程创建的子线程默认为前台线程,后台线程创建的子线程默认为后台线程。

前台死亡之后JVM会通知后台后台线程死亡,而且需要一定时间。要将某个线程设置为后台线程一定要在该线程启动之前设置。

也就是说setDaemon(true)要在start之前,否则将会报IllegalThreadStateException异常。

发表评论

表情:
评论列表 (有 0 条评论,403人围观)

还没有评论,来说两句吧...

相关阅读