【Java中的Thread线程的七种属性的使用和分析】

喜欢博主的关注一下,不喜欢的再看看。٩( •̀㉨•́ )و get!

文章目录

  • 一、Thread的构造方法
  • 二、Thread的常见属性
    • 1.线程ID
    • 2.线程名称
    • 3.线程是否存活
    • 4.是否是后台线程
    • 5.线程优先级
    • 6.线程状态
    • 7.线程中断
      • 中断线程的两种常用方式


参考来自jdk8文档

一、Thread的构造方法

【Java中的Thread线程的七种属性的使用和分析】_第1张图片

常用的构造方法的使用


提示:以下是本篇文章正文内容,下面案例可供参考

二、Thread的常见属性

1.线程ID

  • ID 是线程的唯一标识,不同线程不会重复(相当于人的身份证)
    【Java中的Thread线程的七种属性的使用和分析】_第2张图片

2.线程名称

  • 名称是各种调试工具用到
    【Java中的Thread线程的七种属性的使用和分析】_第3张图片

1和2的代码示例

public class Ceshi {
    public static void main(String[] args) {
    //可以自定义线程的名称,也可以是默认的
        Thread t1 = new Thread();//默认
        Thread t2 = new Thread("t2");
        Thread t3 = new Thread("t3");

        System.out.println("t1的线程ID是:" + t1.getId());
        System.out.println("t2的线程ID是:" + t2.getId());
        System.out.println("t3的线程ID是:" + t3.getId());
        System.out.println("============================");
        System.out.println("t1的名称是:" + t1.getName());
        System.out.println("t2的名称是:" + t2.getName());
        System.out.println("t3的名称是:" + t3.getName());

    }
}

输出结果

【Java中的Thread线程的七种属性的使用和分析】_第4张图片

3.线程是否存活

  • 是否存活,即简单的理解,为 run 方法是否运行结束了

【Java中的Thread线程的七种属性的使用和分析】_第5张图片

代码示例

public class ThreadDemo7 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("Hello t");
        });

        t.start();

        try {
            //t线程没有循环,会迅速执行完毕,t线程结束消失,但是t对象还在
            //让主线程停顿一秒,使t线程先运行结束
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(t.isAlive());//判断t线程是否结束消失
    }
}

输出结果

【Java中的Thread线程的七种属性的使用和分析】_第6张图片


4.是否是后台线程

  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行

【Java中的Thread线程的七种属性的使用和分析】_第7张图片

后台线程

指的是在程序运行期间在后台执行的线程,它不会影响到程序的前台运行。换言之,后台线程不会阻止程序的终止,即使应用程序关闭或主线程终止,后台线程也会继续运行。

前台线程

指的是在程序运行期间在前台执行的线程,它会占用程序的主要资源,如果前台线程阻塞,整个程序都会被阻塞。

代码示例

public class ThreadDemo8 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {
                System.out.println("死循环");
            }
        });

        //默认是前台线程(该t线程必须执行完毕,main线程才能结束),也就是false
        // 改为true,就变成了后台线程(main线程可以直接结束,不管t线程执行过没有)
        t.setDaemon(true);//若将它注释掉,或者改为false,程序就会死循环
        t.start();
    }
}

5.线程优先级

  • 优先级高的线程理论上来说更容易被调度到

Java中线程优先级可以指定,范围是[1, 10](超出这个范围会抛出IllegalArgumentException异常)。

【Java中的Thread线程的七种属性的使用和分析】_第8张图片

上述的 MIN_PRIORITY == 1 和 MAX_PRIORITY == 10

得到线程的优先级

【Java中的Thread线程的七种属性的使用和分析】_第9张图片

代码示例

public class Ceshi {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.print("t1线程-");
        });
        Thread t2 = new Thread(() -> {
            System.out.print("t2线程-");
        });
        Thread t3 = new Thread(() -> {
            System.out.print("t3线程-");
        });
        Thread t4 = new Thread(() -> {
            System.out.print("t4线程-");
        });
        Thread t5 = new Thread(() -> {
            System.out.print("t5线程-");
        });

        //设置线程优先级
        t1.setPriority(10);
        t2.setPriority(6);
        t3.setPriority(3);
        t5.setPriority(9);
        t3.setPriority(7);

        //显示优先级
        System.out.println("t1的优先级为:" + t1.getPriority());
        System.out.println("t2的优先级为:" + t2.getPriority());
        System.out.println("t3的优先级为:" + t3.getPriority());
        System.out.println("t4的优先级为:" + t4.getPriority());
        System.out.println("t5的优先级为:" + t5.getPriority());

        //启动线程,预计执行的顺序 1 5 3 2 4
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();


        System.out.println();
    }
}

输出结果

【Java中的Thread线程的七种属性的使用和分析】_第10张图片
【Java中的Thread线程的七种属性的使用和分析】_第11张图片

两次执行的结果可以看出,这和我们预估的执行顺序有很大的差别,执行多次会发现每次可能都不相同。

原因

  • 简单来说,Java中的优先级来说不是特别的可靠,Java程序中对线程所设置的优先级只是给操作系统⼀个建议操作系统不一定会采纳。而真正的调用顺序,是由操作系统的线程调度算法决定的。(所以一般对线程设置优先级,没有什么意义!

6.线程状态

  • 状态表示线程当前所处的一个情况

【Java中的Thread线程的七种属性的使用和分析】_第12张图片

线程的状态大致有以下几种

  1. NEW
  2. RUNNABLE
  3. BLOCKED
  4. WAITING
  5. TIMED_WAITING
  6. TERMINATED

漫画图解这几种状态的转换
【Java中的Thread线程的七种属性的使用和分析】_第13张图片

可以认为是处于不是 NEW 和 TERMINATED 的状态都是活着的。

简略的状态转移图

【Java中的Thread线程的七种属性的使用和分析】_第14张图片


7.线程中断

  • 中断一个线程

【Java中的Thread线程的七种属性的使用和分析】_第15张图片

【Java中的Thread线程的七种属性的使用和分析】_第16张图片


中断线程的两种常用方式

  1. 自定义的变量来作为标志位
    代码示例
public class ThreadDemo {//自己创建标志位
    public static boolean isQuit = false;//结束标志位,成员变量不受变量捕获的规则限制

    public static void main(String[] args) {
        boolean isQuit1 = false;//lambda受变量捕获的规则限制,只能是final或者实际final(就是如果一个普通变量,第一次赋值后,就再也没有修改过)
        Thread t = new Thread(() -> {
            while (!isQuit) {//!isQuit1
                System.out.println("Hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t线程终止");
        });

        t.start();

        //在主线程中,修改isQuit
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //isQuit1 = true;//会报错,因为这是第二次修改,不符合变量捕获的原则
        isQuit = true;
    }
}
  1. 使用 Thread.interrupted() 或Thread.currentThread().isInterrupted() 代替自定义标志位
  • Thread 内部包含了一个 boolean 类型的变量(Thread.currentThread().isInterrupted())作为线程是否被中断的标记

代码示例

public class ThreadDemo {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            //currentThread 是获取当前的线程实例,即currentThread == t
            //isInterrupted 就是t对象自带的一个标志位
            //默认是false,一直不中断
            //Thread t = Thread.currentThread();
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Hello t");
                try {
                    Thread.sleep(1000);//睡眠阻塞
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //break;//改变标志位后,直接结束
                }
            }
        });

        t.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //1. 把t内部的标志位改为true
        //2. 如果该线程(t线程)正在阻塞(如:sleep()/wait()),此时就会把阻塞状态直接唤醒(通过抛出异常的方式直接让sleep()立即结束)
        t.interrupt();//通知线程该结束了
        //3. sleep()被唤醒后,会自动地把isInterrupted的标志位给清空(true->false)
        //所以抛出异常后,会继续打印Hello t(因为isInterrupted已经改回来了)
    }
}

输出结果

【Java中的Thread线程的七种属性的使用和分析】_第17张图片

  1. 观察标志位是否清除

【Java中的Thread线程的七种属性的使用和分析】_第18张图片

线程默认处于false(不中断)状态

  • Thread.interrupted() 相当于按下开关, 开关自动弹起来了. 这个称为 “清除标志位”
  • Thread.currentThread().isInterrupted() 相当于按下开关之后, 开关弹不起来, 这个称为**“不清除标志位”**

Thread.interrupted() 代码示例

public class Ceshi {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.interrupted());
            }
        });
        t.start();
        t.interrupt();
    }
}

输出结果

【Java中的Thread线程的七种属性的使用和分析】_第19张图片

除了第一次按下,后面的标志位一直处于弹起状态(false,非中断状态)

Thread.currentThread().isInterrupted() 代码示例

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
            	System.out.println(Thread.currentThread().isInterrupted());
            }
        });
        t.start();
        t.interrupt();
    }
}

【Java中的Thread线程的七种属性的使用和分析】_第20张图片

第一次按下之后,后面的标志位一直处于按下状态(true,中断状态)

你可能感兴趣的:(java,开发语言)