目录
1、定义
- Thread类是 JVM用来管理线程的一个类,每个线程都有一个唯一的相关联的Thread对象;
- 每个执行流需要一个对象描述,就是Thread类的对象,JVM讲这些Thread对象组织起来,用于线程调度,线程管理;
2、Thread常见 构造方法
方法 | 功能 |
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用 Runnable 对象创建线程对象 |
Thread(String name) | 创建线程对象,并命名 |
Thread(Runnable target, String name) | 使用 Runnable 对象创建线程对象,并命名 |
Thread(ThreadGroup group, Runnable target) | 线程可以被用来分组管理,分好的组即为线程组 |
代码:
public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println("Thread()构造方法");
});
thread.start();
}
}
public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println("Thread(String name)构造方法");
},"线程 1");
thread.start();
}
3、Thread 的常见属性
属性 | 获取方法 |
id | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
每个线程,都有自己的 状态、优先级、上下文、记账信息
- ID:是线程的唯一标识,不同线程不会重复;
- 名称:获取线程的命名,多用于调试
- 状态:表示线程当前所处的一个情况,下面会着重介绍
- 优先级:优先级高的线程 更容易被调度到(取值:1~10, 1最低,10最高)
- 后台: 后台被守护线程,isDaemon()判断,true为后台线程,false为前台线程
- 线程被创建默认前台线程,前台线程会阻止JVM的退出
- 后台线程不会阻止JVM退出,JVM会在一个进程的所有非后台线程结束后,才会结束运行
- 存活:run()方法是否结束运行,run()没运行 false,正在运行 true
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
System.out.println("Thread(String name)构造方法");
for (int i = 0; i < 5; i++) {
System.out.println("活着那");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("啊!快死了");
},"线程 1");
System.out.println("是否存活:"+thread.isAlive());
thread.start();
System.out.println("ID: "+thread.getId());
System.out.println("Name: "+thread.getName());
System.out.println("状态:"+thread.getState());
System.out.println("优先级:"+thread.getPriority());
System.out.println("后台?:"+thread.isDaemon());
System.out.println("是否存活:"+thread.isAlive());
Thread.sleep(10000);
System.out.println("是否存活:"+thread.isAlive());
}
}
3、休眠线程 sleep()
方法 | 功能 |
public static void sleep(long millis) throws InterruptedException | 休眠当前线程 millis毫秒 |
Thread.sleep() 方法是 Thread类中的一个静态方法,用于使当前线程暂停指定时间(以毫秒为单位)
- 会使当前线程进入阻塞状态,让当前线程暂定执行,让出CPU给其他线程执行,等待指定时间后恢复执行
- 在调用sleep()方法后,线程就是在睡眠时间,如果中断睡眠提前唤醒,就会抛出InterruptedException 异常,捕获后就会对线程中断进行处理;
- sleep() 方法并不是精确的定时器,因为它依赖于系统调度器和其他线程的状态,因此实际的休眠时间可能会比指定的时间略长或略短。
4、启动与中断线程
4.1 start()
调用 start 方法, 才真的在操作系统的底层创建出一个线程,也是将线程启动
4.2 中断线程
中断 就是字面意思,让一个线程停下来,线程终止
本质:让线程的 入口方法执行完毕
- 给线程设置结束标志位
- 调用 interrupt() 方法来通知
4.2.1 设置结束标志位
public static boolean isQuit = false;
public static void main(String[] args) {
Thread thread = new Thread(()->{
while (!isQuit){
System.out.println("活着那");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("啊!要死了");
});
thread.start();
//主线程 修改 isQuit
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//设置isQuit true 终止线程
isQuit = true;
}
注意:
要将标志位设置为静态变量,因为lambda捕获变量必须是final修饰或未被改变的变量
4.2.2 interrupt() 方法
终止线程就是 创建变量来控制循环来结束线程,Thread类 内置类一个标志位,作为线程是否被中断的标记.
方法 | 功能 |
public void interrupt() | 中断当前或指定线程的执行,将中断标志置为true,表示线程已经被中断 |
public boolean isInterrupted() | 用于检查当前线程是否被中断 |
public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println("开始活了");
//currentThread() 返货线程对象 thread
//isInterrupted thread对象里的 自带的标志位 默认false
while (!Thread.currentThread().isInterrupted()){
System.out.println("活着那");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("啊!要死了");
});
//创建线程
thread.start();
//运行 main主线程
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//设置标志位 为true
thread.interrupt();
}
- currentThread()方法 返货线程对象 thread
- isInterrupted()方法 thread对象里的 自带的标志位 默认false
- 调用 sleep() 和 wait() 方法会使线程进入阻塞状态,直到指定的时间到达或者被其他线程唤醒才会继续执行;
- 如果在阻塞期间调用了线程的 interrupt() 方法,则会抛出InterruptedException异常,并将线程的中断标志位设置为 false
- 这样可以让 线程在捕获异常后继续执行或退出;
- 清除中断标志位 的操作是由 JVM的内部实现所产生的;
4.2.3 终止线程
如果不在异常退出,那么线程会继续运行,interrupt() 方法只调用了一次,但 sleep() 和 wait() 方法清除中断标志位,如同电座开关是按钮式,将通路有回弹又打开了
public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println("开始活了");
//currentThread() 返货线程对象 thread
//isInterrupted thread对象里的 自带的标志位 默认false
while (!Thread.currentThread().isInterrupted()){
System.out.println("活着那");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//退出循环
break;
}
}
System.out.println("啊!要死了");
});
4.2.4 为什么会清空中断标志位?
- 调用sleep()方法,线程中断(中断位置设置为true),会抛出异常并将中断标志位清空(设置为false)
- 如果不清空中断标志位,接下来的执行过程中,线程可能会受到中断影响,导致意外结果;清空标志位为了让线程自身能够对线程何时结束有一个明确的控制;
- Interrput()只是通知,不是“命令”,通知线程你该结束了,至于是否结束,立即还是等会由代码灵活控制;
5、等待结束线程 —— join()
线程之间是并发执行的,操作系统对于线程的调度,是无序的;
无法判定两个线程谁先执行,谁后执行;同,结束也不确定;这很不好;
所以,有时候就要明确规定结束顺序,可以用线程等待解决;
方法 | 功能 |
public void join() | 等待线程结束 |
public void join(long millis) | 等待线程结束,最多等 millis 毫秒 |
join()方法,让当前线程等待调用该方法的线程的结束后执行;当前线程暂时进入阻塞状态
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(()->{
for (int i = 0; i < 3; i++) {
System.out.println("thread1 执行");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thread1 执行完毕");
});
thread1.start();
//thread1 调用该方法
//main 等待 thread1结束后执行
thread1.join();
System.out.println("hello main");
}
// thread1 执行
// thread1 执行完毕
// hello main
在哪个线程调用,该线程进入阻塞状态,等待其他线程结束后 退出阻塞继续执行
也有两种情况:
- 死等,其他线程不结束不执行
- 等待指定时间,到时间就退出等待,继续执行