1. Thread 类、常见方法
1.1 常用构造方法
| 方法 | 说明 |
|---|---|
| Thread() | 创建线程对象 |
| Thread( Runnable target) | 使用 Runnable 对象创建线程对象 |
| Thread(String name) | 创建线程对象并命名 |
| Thread( Runnable target ,String name) | 使用 Runnable 对象创建线程对象,并命名 |
1.2 线程的常见属性
| 属性 | 获取方法 |
|---|---|
| ID | getId() |
| 名称 | getNname() |
| 状态 | getState() |
| 优先级 | getPriority() |
| 是否是后台线程 | isDaemon() |
| 是否存活 | isAlive() |
| 是否中断 | isInterrupted() |
获取线程的名称
java
Thread t1 = new Thread();
//给线程起名字
Thread t2 = new Thread("线程2");
Thread t3 = new Thread(new Runnable(){
@Override
public void run(){
}
},"线程3");
//getName 获取线程的名字
System.out.println(t1.getName());
System.out.println(t2.getName());
System.out.println(t3.getName());

线程的名字默认是
Thread - 数字, 给线程起名字,可以在线程数量很多的情况下,更方便地观察线程
1.3 前台线程和后台线程
- 前台线程 : 会阻止进程的结束
- 后台线程 : 不会阻止进程的结束
java
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("thread");
try {
// 睡眠 1 秒
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t线程结束");
});
t.start();
// 睡眠 1 秒
Thread.sleep(1000);
System.out.println("主线程结束");
// main 和 t 都是前台线程 2 个线程都结束 进程才结束
}

进程默认就是前台线程,可以通过
setDaemon(true)把线程设置为 后台线程参数是 true 表示是后台线程, 默认是 false 表示前台线程; 要在线程开启前设置
java
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("thread");
try {
// 睡眠 1 秒
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(" t 线程结束");
});
// 在 strat() 开始前 把 t 设置成 后台线程(守护线程)
t.setDaemon(true);
t.start();
// 睡眠 1 秒
Thread.sleep(1000);
System.out.println("主线程结束");
// 前台线程结束了 进程就结束
}

1.4 start( )
strart()会调用操作系统的 API , 在操作系统中创造出一个线程Java为了让一个 thread 对象和 一个操作系统线程 一一对应, 每个线程只能调用一次
start()
java
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println("t1 thread");
});
t1.start();
t1.start();
}

1.5 中断线程
中断线程的 2 种方式 :
- 通过共享标记进行沟通
- 通过调用 interrupt( ) 方法
使用自定义变量作为标识位
java
private static boolean running = true;
public static void main(String[] args) {
Thread t = new Thread(() -> {
while(running){
System.out.println("thread t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
try {
//睡眠 4 秒后 中断线程
Thread.sleep(4000);
running = false;
}catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

使用 interrupt( )
java
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
// currentThread 获取 t 线程的引用
Thread cur = Thread.currentThread();
//isInterrupted 判断 t 线程的标识位
while (!cur.isInterrupted()) {
System.out.println("thread");
try {
//预计 sleep 100 秒
Thread.sleep(100_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
Thread.sleep(1000);
// 设置 t 线程的标识位
t.interrupt();
}
interrupt()能设置标志位,还能唤醒 sleep 等导致线程堵塞的方法

Q :为什么这里会在线程中止后又打印 thread ?
A :
interrupt()设置标识位为true唤醒sleep(),让sleep()抛出异常后,sleep()自动重新设置标识位为false
Thread.currentThread(): 获取当前线程的引用
javapublic static void main(String[] args) { //获取主线程的引用 Thread mainThread = Thread.currentThread(); System.out.println(mainThread.getName()); }如果在主线程执行
Thread.currentThread()就是获取主线程的引用;在
thread1线程中执行Thread.currentThread()就是获取thread1线程的引用
1.6 join( ) 线程等待
java
private static int sum = 0;
public static void main(String[] args) {
Thread t = new Thread(() -> {
for (int i = 1; i <= 1000; i++) {
sum += i;
}
});
t.start();
System.out.println("sum = " + sum);
}
要求是 :等 t 线程计算完 1~1000 的和之后, 主线程再进行打印和

结果是
t线程还没有计算, 主线程就打印结果了,如果使用sleep()让 主线程睡一会,睡少了t 线程还没有计算完,睡多了又浪费时间,另外如果t 线程的逻辑复杂,sleep()就更不适用,这时使用join()就能让一个线程执行结束后,再继续执行
| 方法 | 说明 |
|---|---|
| join() | 当前线程一直等待,直到目标线程执行完毕才继续 |
| join( long millis ) | 当前线程最多等待 millis 毫秒,超时后无论目标线程是否结束,当前线程都会继续执行 |
java
private static int sum = 0;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
for (int i = 1; i <= 1000; i++) {
sum += i;
}
});
t.start();
t.join();
System.out.println("sum = " + sum);
}

join()如果目标线程一直不结束,那就会一直等下去
java
public static void main(String[] args) throws InterruptedException {
//获取 main 线程的引用
Thread main = Thread.currentThread();
System.out.println("开始等待");
main.join();
System.out.println("线程结束");
}

join( long millis )等待设置的 ms 后继续执行
java
public static void main(String[] args) throws InterruptedException {
//获取 main 线程的引用
Thread main = Thread.currentThread();
System.out.println("开始等待");
//等待 2 秒
main.join(2000);
System.out.println("线程结束");
}

如果调用
join前线程就已经执行完了,再次调用join是线程不会堵塞
2. 线程的状态
线程的 6 种状态
| 状态 | 表示 |
|---|---|
| NEW | 创建了 Thread 对象但没有 start() |
| TERMINATED | 操作系统线程销毁(线程的执行入口执行完了),但 thread 对象还在 |
| RUNNABLE | 可运行的 1.CPU 正在执行 2.等待CPU调度执行(就绪) |
| WAITING | 线程无限等待 调用无参 join(),目标线程不结束,等待进程的状态 |
| TIMED_WAITING | 线程有限等待 调用join(long millis) 过程中,等待进程的状态 |
| BLOCKED | 由于锁导致的堵塞 |
NEW 、RUNNABLE 、TERMINATED 状态的转换
java
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
});
System.out.println(t.getState());
t.start();
System.out.println(t.getState());
t.join();
System.out.println(t.getState());
}

WAITING
java
public static void main(String[] args) throws InterruptedException {
Thread mainThread = Thread.currentThread();
Thread t = new Thread(() -> {
while(true){
System.out.println("mainThread state " + mainThread.getState());
}
});
t.start();
t.join();
}

TIMED_WAITING
java
public static void main(String[] args) throws InterruptedException {
Thread mainThread = Thread.currentThread();
Thread t = new Thread(() -> {
while(true){
System.out.println("mainThread state " + mainThread.getState());
}
});
t.start();
t.join(10000);
}
