Thread类
线程常见构造方法

其中第三、第四构造方法,可以给线程起名字。
如果不起名字默认Thread-0、Thread-1......

Thread 常见属性

ID式线程的唯一标识,不同线程不会重复
状态表示线程当前所处的情况(阻塞 / 就绪)
优先级高的线程理论上更容易被调度
关于后台线程,JVM会在一个进程的所有非后台线程结束后,才会结束运行.
是否存活,简单的理解是run方法是否运行结束了
代码中,创建的Thread对象的生命周期,和系统中实际线程的生命周期可能不同,可能会出现Thread对象仍然存在,但是内核中的线程不存在的情况
1)调用start方法之前,系统中,还没创建线程
2)线程的run执行完毕后,线程就结束了,但Thread对象,仍然存在
后台线程
某个线程在执行过程中,不能阻止进程结束(虽然线程还在执行,但进程要结束了,此时这个线程会随着进程的结束而结束),这样的线程就是"后台线程".
前台线程
某个线程在执行过程中,能够阻止进程结束,这样的线程就是"前台线程".
线程的核心操作
1. 创建线程 start
start 和 run之间的区别
start:调用系统函数,在系统内核中,创建线程,创建好的线程再来单独执行run。(此处的 start,会根据不同的操作系统,来分别调用不同的api)
run:描述线程要执行的任务,也可以称为"线程的入口"
调用 start ,不一定是main线程调用。任何线程都可以创建其他线程,如果系统资源充裕,可以任意创建线程。
一个Thread对象,只能调用一次 start,如果多次调用,会报以下异常
(一个Thread对象,只能对应系统中的一个线程)

2. 线程的中断

1.自定义变量作为标志位
java
public class Demo17 {
private static boolean isQuit = false;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while(!isQuit) {
System.out.println("hello,Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("线程执行结束");
});
t.start();
Thread.sleep(2000);
System.out.println("main 线程尝试终止 t 线程");
isQuit = true;
}
}

2. 使用Thread.Interrupted()或Thread.currentThread().isInterrupted()
Thread 内部包含了一个boolean 类型的变量作为线程是否被中断的标记
初始情况下,变量为false
但若有其他线程,调用interrupt方法,会设置上述标志位
java
public class Demo18 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
//获取线程的引用
Thread currentThread = Thread.currentThread();
while (!currentThread.isInterrupted()) {
System.out.println("hello,Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
Thread.sleep(3000);
//在主线程中,控制 t 线程终止,设置上述标志位
t.interrupt();
}
urrentThread() 是 Thread 类的静态方法.调用此方法就能获取到调用此方法的线程实例(作用类似this)
但执行代码时,出现了以下异常
由于catch中 默认代码再次抛出异常,但再次抛出的异常,没有再次被catch,那么进程就直接异常终止

根本原因是 sleep/wait/join 等阻塞的方法被唤醒之后,会清空刚才设置的interrupted标志位,导致代码一直在循环
因此,要想结束循环,结束线程,需要在 catch 中加 return / break .
线程等待
操作系统,针对多个线程的执行,是一个"随机调度,抢占式执行"的过程。而线程等待,就是在确定两个线程的"结束顺序".
具体逻辑:让后结束的线程,等待先结束的线程即可,此时后结束的线程就会进入阻塞,一直到先结束的线程,真的结束了,阻塞才接触
假设现在有线程a,b
在a线程中调用 b.join 意思就是让a线程等待b线程,直到b线程结束,然后a再继续执行.
java
public class Demo19 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
for(int i = 0; i < 3 ; i++){
System.out.println("这是t线程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t线程结束");
});
t.start();
System.out.println("主线程开始等待");
//main线程开始等待 t线程
try {
t.join();
}catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("主线程等待结束");
}
}


任何线程之间都是可以互相等待的,线程等待不止可以存在于两个线程之间,也可以同时等待多个其他线程,或若干线程之间互相等待.
创建t1,t2线程,并让t2等待t1,主线程等待t1、t2
java
public class Demo20 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
for(int i = 0; i < 5; i++ ){
System.out.println("这是t1线程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t1线程执行结束");
});
Thread t2 = new Thread(()->{
for(int i = 0; i < 3; i++){
System.out.println("这是t2线程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
try {
//t2线程 等待 t1线程
t1.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("t2线程结束");
});
t1.start();
t2.start();
System.out.println("main线程开始等待");
t1.join();
t2.join();
System.out.println("main线程等待结束");
}
}
我们来观察以下代码,先不考虑t1.join(),那么在t1,t2线程同时创建,同时执行逻辑时,那么应该t2线程先结束。因为 t1 要打印5次,而 t2 只需打印3次

t1,t2线程创建之后,和主线程一起同时执行逻辑,但由于主线程中的 t1.join,t2.join ,那么主线程先等待t1,t2线程执行逻辑。然后当 t2 打印三次之后又遇到了 t1.join,那么t2 开始等待 t1。所以出现了 t1线程执行结束,t2 线程结束,main线程结束的顺序。

其他线程等待
获取当前线程引用

java
public class Demo21 {
public static void main(String[] args) {
Thread t = Thread.currentThread();
System.out.println(t.getName());
}
}
这也说明了,main 主线程的存在

线程状态
既然说到线程状态,那么我们不得不说一下它的"爸爸"进程的进程状态
进程状态:
就绪:正在 cpu 上执行,或者随时可以去 cpu 上执行
阻塞:暂时不能参与 cpu 执行
线程的六种状态
- NEW
当前 Thread 对象存在,但没有分配线程(即还没调用start)
- TERMINATED
当前 Thread 对象存在,但线程已经结束
- RUNNABLE
就绪状态:正在 cpu 上运行 或 随时可以去 cpu 上执行
- BLOCKED
因为 锁 竞争,引起的阻塞
- TIMED_WAITING
有时间限制的线程等待
- WAITING
没有时间的线程等待