转载

Java_多线程---线程状态的控制方法(续...多线程的状态)

一、大纲

  • sleep()
  • yield()
  • join()
  • 线程优先级
  • 高效结束线程

二、详述

  • 2.1、 线程睡眠—— sleep()

    • 注意 :

      • ①、 sleep()静态方法 ,最好不要用Thread的实例 对象 调用它,因为它睡眠的始终是当前正在运行的线程,而不是调用它的线程对象,它只对正在运行状态的线程对象有效。
      • ②、 Java 线程调度 是Java多线程的 核心 , 但是不管程序员怎么编写调度,只能最大限度的影响线程执行的 次序 ,而不能做到精准控制。因为
        sleep() -> 阻塞状态 -> 就绪状态 -> 运行状态。
        而就绪状态进入到运行状态,是由系统控制的
  • 2.2、 线程礼让—— yield()

    • 性质:

      • 一个静态的方法
      • yield() 方法只是让当前线程 暂停 一下,重新进入就绪的线程池中,让系统的线程调度器重新调度器 重新调度一次 ,所以有可能刚进入就绪状态,又被调度到运行状态
      • 让出cpu资源给其他的线程。
    • sleep() 的区别

      • ①、 sleep() 方法暂停当前线程后,会进入 阻塞 状态,只有当睡眠时间到了,才会转入 就绪 状态。
        yield() 方法调用后 ,是直接进入 就绪 状态,所以有可能刚进入就绪状态,又被调度到 运行 状态。
      • ③、 sleep() 声明抛出了 InterruptedException ,所以调用 sleep() 方法的时候要捕获该异常,或者显示声明抛出该异常。
        yield() 方法则没有声明抛出任务异常。
      • ③、 sleep() 方法比 yield() 方法有更好的 可移植性 ,通常 要依靠 yield() 方法来控制并发线程的执行。
  • 2.3、 线程合并 (插队)—— join()

    • 性质: 线程 1 使用 join() 后,线程 2 必须等待线程1执行完毕才能执行!,常常在一个线程的内部的 run() 方法,进行另一个线程的 join() (插队)
    • 重载版本

      • void join(); 当前线程等该加入该线程后面,等待该线程终止。
      • void join(long millis)

        • 当前线程等待该线程终止的时间最长为 millis 毫秒。 如果在millis时间内,该线程没有执行完,那么当前线程进入就绪状态,重新等待cpu调度。
      • void join(long millis,int nanos)

        • 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。如果在millis时间内,该线程没有执行完,那么当前线程进入就绪状态,重新等待cpu调度
  • 2.4、 线程优先级 —— Priority

    • 性质:

      • 每个线程执行时都有一个优先级的属性
      • 优先级低只是意味着 获得调度 的概率低。并不是绝对先调用优先级高的线程后调用优先级低的线程。
      • 线程休眠 类似,线程的优先级仍然无法保障线程的 执行次序
      • 每个线程默认的优先级都与创建它的父线程具有 相同 的优先级,在默认情况下, main 线程具有普通优先级
    • 使用: Thread 类提供了

      • setPriority(int newPriority) 设置1个指定线程的优先级
      • getPriority() 返回1个指定线程的优先级
      • 范围是 1 ~ 10 之间
      • 推荐使用 Thread 类的静态成员变量进行设置,这样才能保证程序最好的可移植性。
        MAX_PRIORITY = 10
        MIN_PRIORITY = 1
        NORM_PRIORITY = 5
  • 2.5、 守护线程

    • 性质:

      - 它为用户线程提供后台支持任务的服务。
      - 它在生命中没有为服务用户线程而发挥作用。
      - 它的生命取决于用户线程。它是一个低优先级的线程。
      - **用户线程都执行完,JVM会终止守护程序线程**
    • 应用实例(守护线程通常用于执行一些后台作业)

      • JVM 的垃圾回收、内存管理等线程都是守护线程
      • 数据库连接池,连接池本身也包含着很多后台(守护)线程,监控连接个数、超时时间、状态等等。
      • 应用程序运行时播放背景音乐,在文字编辑器里做自动语法检查、自动保存等功能。
      • 如果将这个播放背景音乐的线程设定为 守护线程,那么在用户请求退出的时候,不仅要退出主线程,还要通知播放背景音乐的线程退出;如果设定为守护线程则不需要了
    • 使用方法

      public final void setDaemon(boolean on);`
       
        Thread t = new Thread( () -> {
            public void run() { //do something; }
        });
        t.setDaemon(true);    //该方法必须在 start() 启动线程前调用。
        t.start();
      • 可能的异常

        IllegalThreadStateException - 如果该线程处于活动状态。     
        SecurityException - 如果当前线程无法修改该线程。
  • 2.6、 如何高效地结束一个线程!

    • TipThread.stop()、Thread.suspend、Thread.resume、Runtime.runFinalizersOnExit 这些终止线程运行的方法已经被废弃了,使用它们是极端不安全的!
    • 常用方法

      • 1、正常执行完 run() 方法,然后结束掉

        class MyThread extends Thread { 
               int i=0; 
               @Override
               public void run() { 
                  while (true) 
                  { 
                     if (i == 10) 
                        break; 
                     i++; 
                     System.out.println(i); 
                  } 
               } 
          }
      • 2、控制循环条件和判断条件的标识符来结束掉线程

        class MyThread extends Thread { 
               int i = 0; 
               boolean next = true; 
               @Override
               public void run() { 
                  while (next) 
                  { 
                     if(i == 10) 
                         next = false; 
                     i++; 
                     System.out.println(i); 
                  } 
               } 
           }
  • 3、使用 interrupt() 这个巧妙的方式结束掉这个线程

    • 3.12 种方法的标识符来结束一个线程,是一个不错的方法,但如果,该线程是处于 sleep()、wait()、join() 的状态的时候, while 循环就不会执行,那么我们的 标识符 就无用武之地了,
    • 3.2 我们看看 sleep()、wait()、join() 方法的声明:

      public final void wait() throws InterruptedException 
       public static native void sleep(long millis) throws InterruptedException 
       public final void join() throws InterruptedException
      • 三者有一个共同点,都抛出了一个 InterruptedException 的异常。
    • 3.3 在什么时候会产生这样一个异常呢?

      • 当一个线程处于 sleep()、wait()、join() 这三种状态之一的时候,如果此时它的中断状态为 true ,那么它就会抛出一个 InterruptedException 的异常,并会将中断状态重新设置为 false
    • 3.4 例子

      public class Test {
            public static void main(String[] args) throws InterruptedException    
            {
                MyThread thread=new MyThread();
                thread.start();
            }
        }
        class MyThread extends Thread {
            int i = 1;
            @Override
            public void run()
            {
                while (true)
                {
                    System.out.println(i);
                    System.out.println(this.isInterrupted());
                    try{
                        System.out.println("我马上去sleep了");
                        Thread.sleep(2000);
                        this.interrupt(); //interrupt()方法将中断状态设置为true
                    }
                    catch (InterruptedException e){
                        System.out.println("异常捕获了" + this.isInterrupted());
                        return;
                    }
                    i++;
                }
            }
        }结果:
        1. 1  
        2. false  
        3. 我马上去sleep了  
        4. 2  
        5. true  
        6. 我马上去sleep了  
        7. 异常捕获了false 
         (1)首先执行第一次while循环,在第一次循环中,睡眠2秒,然后将中断状态设置为true。
         (2)当进入到第二次循环的时候,中断状态就是第一次设置的true,当它再次进入sleep的时候,
            马上就抛出了InterruptedException异常
         (3)然后被我们捕获了。
         (4)然后中断状态又被重新自动设置为false了(从最后一条输出可以看出来)
原文  https://segmentfault.com/a/1190000019824140
正文到此结束
Loading...