<JavaEE> Thread线程类 和 Thread的常用方法

目录

一、Thread概述

二、构造方法

三、常用方法

[1.1 getId()、getName()、getState()、getPririty()](#1.1 getId()、getName()、getState()、getPririty())

[1.2 start()](#1.2 start())

[1.3 isDaemon()、setDaemon()](#1.3 isDaemon()、setDaemon())

[1.4 isAlive()](#1.4 isAlive())

[1.5 currentThread()](#1.5 currentThread())

[1.6 Interrupt()、interrupted()、isInterrupted()](#1.6 Interrupt()、interrupted()、isInterrupted())

[1.6.1 方法一:添加共享的标志位](#1.6.1 方法一:添加共享的标志位)

[1.6.2 方法二:使用内置的标志位](#1.6.2 方法二:使用内置的标志位)

[1.6.3 Java中终止线程不是强制性的](#1.6.3 Java中终止线程不是强制性的)

[1.7 sleep()](#1.7 sleep())

[1.8 join()](#1.8 join())


一、Thread概述

|----------------------------------------------------------------------------------------------|
| Thread类是JVM用于管理线程的类,每一个线程都与一个唯一的Thread对象相关联,即每个执行流都由一个Thread对象进行描述,这些对象被JVM组织,用于线程调度和管理。 |


二、构造方法

|-------------------------------------------|---------------------------------------|
| 构造方法 | 说明 |
| Thread() | 创建线程对象 |
| Thread(Runnable target) | 使用Runnable接口实现类对象,创建线程对象 |
| Thread(String name) | 创建线程对象,并为线程对象命名 |
| Thread(Runnable target, String name) | 使用Runnable接口实现类对象,创建线程对象,并为线程对象命名 |
| Thread(TreadGroup group, Runnable target) | 指定线程组,使用Runnable接口实现类对象,创建线程对象 |


三、常用方法

|---------------------|-----------------------|
| 常用方法 | 说明 |
| getId() | 获取线程ID |
| getName() | 获取线程名 |
| getState() | 获取线程状态 |
| getPririty() | 获取线程优先级 |
| start() | 启动线程 |
| isDaemon() | 判断线程是否为后台线程(守护线程) |
| setDaemon() | 设定线程是否为后台线程(守护线程) |
| isAlive() | 判断线程是否"存活" |
| currentThread() | 获取当前线程的引用 |
| Interrupt() | 终止一个线程 |
| interrupted() | 判断当前线程标志位状态 |
| isInterrupted() | 判断对象线程标志位状态 |
| sleep() | 休眠线程 |
| join() | 阻塞线程 |

1.1 getId()、getName()、getState()、getPririty()

|---------------------------------------|
| getId() |
| 获取线程ID,ID是线程的唯一标识,由JVM自动分配并确保唯一性。 |

|-------------------------------------|
| getName() |
| 获取线程名,线程名可以自动生成,也可以自定义。线程名可以重复。 |

|-------------------------------------------------------------|
| getState() |
| 获取线程状态,线程的状态有就绪、阻塞等。Java中现成的状态使用枚举保存,可以通过遍历枚举获得所有状态的描述。 |

阅读指针 -> 《Java中线程有多少种状态(State)?状态之间的关系有什么关系?》

<JavaEE> Java中线程有多少种状态(State)?状态之间的关系有什么关系?-CSDN博客文章浏览阅读3次。介绍Java中的线程状态和状态之间的关系有什么关系。https://blog.csdn.net/zzy734437202/article/details/134626843

|------------------------------------------------|
| getPririty() |
| 获取线程优先级,优先级高的线程理论上更容易被调度使用,但是在Java中优先级的效果并不明显。 |

++操作演示:++

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println("这是MyThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Thread_Demo6 {
    public static void main(String[] args){
        Thread thread = new MyThread();
        System.out.println("ID:"+thread.getId());
        System.out.println("线程名:"+thread.getName());
        System.out.println("状态:"+thread.getState());
        System.out.println("优先级:"+thread.getPriority());
    }
}

++打印结果:++

ID:20

线程名:Thread-0

状态:NEW

优先级:5

1.2 start()

|------------------------------------------------------------------------------------|
| start() 启动线程 |
| 1)通过重写Thread中的run方法可以创建一个线程对象,再通过调用start()方法,启动这个线程。此时,操作系统中的线程才真正被创建出来。 |
| 2)Thread调用start()创建出的线程,底层仍然是调用系统的API来进行创建线程的操作。 |
| 3)Thread类使用start方法启动线程,对于同一个Thread对象,start方法只能调用一次,需要启动多少个线程,就需要创建多少个Thread对象。 |
| 4)start()和run()的区别在于,run方法是提供了线程需要运行的内容,而start方法才是真正让线程运行起来。 |

++同一个Thread对象不能多次调用start方法演示:++

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=0;i<2;i++){
            System.out.println("这是MyThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("MyThread-run()运行结束");
    }
}
public class Thread_Demo9 {
    public static void main(String[] args) {
        Thread thread = new MyThread();

        //第一次启动线程thread;
        thread.start();

        //第二次启动线程thread;
        thread.start();
    }
}

++打印结果:++

Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:708)
at Learn_Thread.Demo9.Thread_Demo9.main(Thread_Demo9.java:32)

这是MyThread

这是MyThread

MyThread-run()运行结束


可以看到两次调用start方法,只有一次成功执行,另一次报错IllegalThreadStateException

1.3 isDaemon()、setDaemon()

|-----------------------------------------------------------------------------------|
| isDaemon() 判断线程是否为后台线程 |
| setDaemon() 设定线程是否为后台线程 |
| 1)daemon的意思是守护,因此也将后台线程称为守护线程。与后台线程相呼应,还有前台线程。 |
| 2)代码创建的线程,默认为前台线程。当setDaemon()方法的参数为false时,线程将被设置为前台线程,当参数为true时,线程将被设置为后台线程。 |
| 3)前台线程的运行时,将阻止进程结束;后台线程运行时,不会阻止进程结束。 |
| 4)因此为什么将后台线程称为守护线程?就是说进程需要我就在,进程不要我就走,在背后默默守护进程的线程嘛??? |

++后台进程的执行演示:++

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println("这是MyThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Thread_Demo7 {
    public static void main(String[] args) {
        Thread thread = new MyThread();

        //设置为守护线程(后台线程);
        thread.setDaemon(true);
        //开始thread;
        thread.start();

        //main线程等待两秒后结束,此时守护线程还有代码没打印,但也随之结束了;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main线程结束");
    }
}

++打印结果:++

这是MyThread

这是MyThread

main线程结束


启动main线程和thread线程,在main线程sleep两秒结束线程后,可以看到thread线程的run()方法打印结果确实不是预期中的五次"这是MyThread"。这意味着thread线程也随着main线程的结束而结束了。

1.4 isAlive()

|---------------------------------------------------------------------------------|
| isAlive() 判断线程是否"存活" |
| 1)Java中的线程类Thread对象实例,虽然表示一个线程,但这个实例的生命周期与系统内核中的线程的生命周期是不同的。 |
| 2)Thread对象创建了就存在,但此时如果调用isAlive()得到的结果将会是false,因为内核中的线程此时还不存在。 |
| 3)只有当调用start()启动线程之后,内核中的线程启动,调用isAlive()得到的结果才会是true。 |
| 4)当线程运行结束,系统内核中的线程也随之结束,此时虽然Thread对象还存在,但是调用isAlive()得到的结果也将是false。 |
| 5)因此,可以简单将这个方法认为是用于判断系统内核中的线程(PCB)是否存在。 从代码层面来讲,可以认为是用于判断run()方法是否执行完毕。 |

++演示判断线程是否"存活":++

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=0;i<2;i++){
            System.out.println("这是MyThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("MyThread-run()运行结束");
    }
}
public class Thread_Demo8 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();

        //线程已有实例,判断isAlive();
        System.out.println("start前,thread是否存活:"+thread.isAlive());

        //启动线程,判断isAlive();
        thread.start();
        System.out.println("start中,thread是否存活:"+thread.isAlive());

        //等待run()执行结束,此时实例依旧存在,判断isAlive();
        Thread.sleep(5000);
        System.out.println("start结束,thread是否存活:"+thread.isAlive());
    }
}

++打印结果:++

start前,thread是否存活:false
start中,thread是否存活:true

这是MyThread

这是MyThread

MyThread-run()运行结束
start结束,thread是否存活:false

1.5 currentThread()

|------------------------------------------------------------|
| currentThread() 获取当前线程的引用 |
| 1)在currentThread()方法返回的打印信息中,有三个值,分别代表[线程名,线程优先级,所在线程组]。 |

++获取线程引用操作演示:++

java 复制代码
public class Thread_Demo11 {
    public static void main(String[] args) {
        //打印main线程信息;
        System.out.println(Thread.currentThread());
    }
}

++打印结果:++

Thread[main,5,main]


中括号中的三个值分别代表:线程名,线程优先级,所在线程组。

1.6 **Interrupt()、interrupted()、**isInterrupted()

++如果想要中断(终止)一个线程,可以有多种方法,以下介绍两种:++

|----------|----------------------|
| 方法一: | 通过共享的标志进行线程间沟通。 |
| 方法二: | 调用Interrupt()方法。 |

1.6.1 方法一:添加共享的标志位

java 复制代码
class MyThread extends Thread{
    //设置共享的标志位;
    public volatile boolean isQuit = false;
    @Override
    public void run() {
        //根据标志位的变化,决定后续执行;
        while (!isQuit){
            System.out.println("这是MyThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("MyThread-run()运行结束");
    }
}
public class Thread_Demo10 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();
        //启动线程;
        thread.start();

        //延时两秒后更改标志位;
        Thread.sleep(2000);
        ((MyThread) thread).isQuit = true;
    }
}

++打印结果:++

这是MyThread

这是MyThread

这是MyThread

MyThread-run()运行结束

1.6.2 方法二:使用内置的标志位

|-----------------------------------------|----------------------------------------------|
| 方法 | 说明 |
| public void interrupt() | 如果线程处于阻塞状态,则抛出异常; 如果线程不处于阻塞状态,则终止线程。 |
| public static boolean interrupted() | 判断当前线程标志位状态。 |
| public boolean isInterrupted() | 判断对象线程标志位状态。 |
| 1)上文由程序员手动设置了一个共享的标志位,用于控制线程的执行。Java中也提供了相应的封装好的方法,内置了标志位。使用以上三个方法,一样可以达到控制线程的执行效果。 ||

++通过Interrupt()终止线程,然后对线程标志位状态进行判断:++

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        //使用isInterrupted()判断标志位状态;
        while (!Thread.currentThread().isInterrupted()){
            System.out.println("这是MyThread");

            //打印当前线程标志位的状态;
            System.out.println(Thread.interrupted());
        }
        System.out.println("MyThread-run()运行结束");
    }
}
public class Thread_Demo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();

        //延时两秒后更改标志位;
        Thread.sleep(2000);
        thread.interrupt();
    }
}

++打印结果:++

......

这是MyThread

false

这是MyThread

false

这是MyThread

false

MyThread-run()运行结束


休眠两秒后,thread通过调用interrupt()方法修改了标志位,线程终止执行。

++当更改标志位,但线程处于阻塞状态时:++

|------------------------------------------------------------------------------------------------------------------|
| 在更改标志位时,如果线程因为调用 wait/join/sleep 等方法而阻塞,则此时会抛出异常InterruptedException,并重置终止标志位。此时程序的后续执行通过catch子句中的异常处理方案来决定。 |
| 如果在更改标志位时,线程非为阻塞状态,则标志位不会重置,可以通过interrupted()或isInterrupted()进行判断。 |

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()){
            System.out.println("这是MyThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("MyThread-run()运行结束");
    }
}
public class Thread_Demo14 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();

        //等待两秒后唤醒;
        Thread.sleep(2000);
        thread.interrupt();
    }
}

++打印结果:++

这是MyThread

这是MyThread
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at Learn_Thread.Demo14.MyThread.run(Thread_Demo14.java:16)

这是MyThread

这是MyThread

这是MyThread


可以看到,在抛出异常后,仍然继续打印,这意味着原先由interrupt()方法修改的标志位,在sleep唤醒时,又被重置为false了。

++在异常处理中,加入更多的处理方法:++

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()){
            System.out.println("这是MyThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                //在异常处理中加入break,跳出循环;
                break;
            }
        }
        System.out.println("MyThread-run()运行结束");
    }
}
public class Thread_Demo14 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();

        //等待两秒后唤醒;
        Thread.sleep(2000);
        thread.interrupt();
    }
}

++打印结果:++

这是MyThread

这是MyThread
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at Learn_Thread.Demo14.MyThread.run(Thread_Demo14.java:16)

MyThread-run()运行结束


线程通过interrupt()方法修改了标志位,但由于线程此时大概率处于sleep(即,阻塞状态),因此,抛出异常,并将标志位重置。

这里线程会终止,是由异常处理中的break跳出循环得到的结果。

1.6.3 Java中终止线程不是强制性的

|-----------------|---------------------------------------------------------------------------------------------------------------------------|
| 操作系统中的API: | 提供了强制终止线程的操作,无论线程执行到何种程度,都强行结束线程。 |
| Java中的的API: | 终止线程需要对应线程互相配合,而不是直接"剪断"。 |
| 优劣: | 强制结束线程的方式更"随心所欲,为所欲为",但如果线程执行过程中被强行终止,可能导致出现一些临时性质的"错误"数据 。而相互配合的线程终止,虽然使终止线程时需要考虑的事情变多了,但也使得线程的终止更"安全",系统运行更稳定了。 |

1.7 sleep()

|----------------------------------------------------------------------------------|---------------------|
| 方法 | 说明 |
| public static void sleep(long millis) throws InterruptedException | 以毫秒级别的精度,指定休眠时间 |
| public static void sleep(long millis, int nanos) throws InterruptedException | 以纳秒级别的精度,指定休眠时间 |

|------------------------------------------------------------------|
| 1)sleep()方法只能保证实际休眠时间大于等于参数设置的休眠时间。 |
| 2)sleep被提前唤醒(如被上文的interrup唤醒)时,会抛出异常,并将Thread对象的标志位重置为false。 |

++sleep被提前唤醒时,为什么要重置标志位?++

|-----------------------------------------------------------------------------------|
| sleep重置标志位,可以给程序员更多的"可操作空间"。 通过抛出异常,处理异常,程序的后续执行可以且不仅可以让线程立即结束,增加了代码的灵活性。 |

1.8 join()

|--------------------------------------------------------------|
| join() 等待线程结束 |
| join(long millis) 等待线程结束,指定最长等待时间 |
| join(long millis, int nanos) 等待线程结束,以纳秒级别的精度指定最长等待时间 |
| 1)由于随即调度,抢占式执行,多线程的执行顺序是不确定的。但是通过应用程序中的API,可以影响到线程的执行顺序。 |

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println("这是MyThread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("MyThread-run()运行结束");
    }
}
public class Thread_Demo13 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();

        //让主线程阻塞,保证MyThread先运行完;
        thread.join();
        System.out.println("在MyThread结束后打印");
    }
}

++打印结果:++

这是MyThread

这是MyThread

这是MyThread

这是MyThread

这是MyThread

MyThread-run()运行结束

在MyThread结束后打印


可以看到,main线程中的"在MyThread结束后打印"确实是在thread线程结束后才打印的。


阅读指针 -> 《线程安全(重点!!)》

链接生成中..........

相关推荐
Wlq04152 小时前
J2EE平台
java·java-ee
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】Thread类的方法&线程生命周期
java·开发语言·java-ee
阑梦清川2 小时前
JavaEE初阶---网络原理(五)---HTTP协议
网络·http·java-ee
杨荧4 小时前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
XiaoLeisj14 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
尢词19 小时前
SpringMVC
java·spring·java-ee·tomcat·maven
阑梦清川1 天前
JavaEE进阶---第一个SprintBoot项目创建过程&&&我的感受
java·java-ee·springboot
移民找老国1 天前
加拿大移民新风向
java-ee·maven·phpstorm·visual studio code·nio
琪露诺大湿1 天前
JavaEE-多线程初阶(4)
java·开发语言·jvm·java-ee·基础·1024程序员节·原神