目录
Java 并发线程基础
线程的状态
-
NEW:初始状态,线程被创建,但是还没有调用start()方法。
-
RUNNABLE:运行状态,Java线程将操作系统中的就绪和运行两种状态笼统地称作"运行中"
-
BLOCKED:阻塞状态,表示线程阻塞于锁。
-
WAITING:等待状态,表示线程进入等待状态,进入该状态表示当前线程需要等待其他线程做出一些等待动
作 (通知或中断) -
TIME_WAITING:超时等待状态,该状态不同于WAITING状态,它可以在指定的时间自行返回。
-
TERMINATED:终止状态,表示当前线程已经执行完毕。
线程的构造方式
- Java不支持多重继承,因此继承了Thread类就无法继承其它类,但是可以实现多个接口;
- 类可能只要求可执行就行,继承整个Thread类开销过大。
第一种:继承 Thread
类
基本结构
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 调用start()而不是run()
}
}
核心原理
Thread
本质上实现了Runnable
接口。- 调用
start()
方法会:- 创建新的线程栈;
- 调用底层
start0()
native 方法; - JVM 安排线程调度,自动调用
run()
方法中的代码;
- 如果你直接调用
run()
方法,其实就是普通方法调用,不会创建线程。
使用建议
- 不推荐生产中使用,因为:
- 单继承限制扩展性;
- 难以实现资源共享。
第二种:实现 Runnable
接口
基本结构
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程执行:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
Runnable task = new MyRunnable();
Thread thread = new Thread(task);
thread.start();
}
}
核心原理
Runnable
是一个函数式接口,只有一个run()
方法;Thread
构造方法支持接收Runnable
实例,然后内部委托执行run()
。
public class Thread implements Runnable {
private Runnable target;
public Thread(Runnable target) {
this.target = target;
}
public void run() {
if (target != null) {
target.run();
}
}
}
使用建议
- 推荐使用;
- 更适合多个线程共享同一个任务(实现资源共享、计数器等);
- 不支持直接返回结果,但配合外部变量可解决。
第三种:实现 Callable
+ FutureTask
基本结构
import java.util.concurrent.*;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("线程执行:" + Thread.currentThread().getName());
return 42;
}
public static void main(String[] args) throws Exception {
Callable<Integer> task = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(task);
Thread thread = new Thread(futureTask);
thread.start();
Integer result = futureTask.get(); // 阻塞获取结果
System.out.println("返回结果:" + result);
}
}
核心原理
Callable
接口是 JDK5 引入的新特性;- 和
Runnable
不同,它可以:- 有返回值;
- 抛出异常;
FutureTask
是Runnable
的实现类,也实现了Future
接口,兼容Thread
。
使用建议
- 当希望线程能返回执行结果,如任务处理、计算类任务;
- 可结合线程池使用(例如
ThreadPoolExecutor.submit()
接收 Callable);
线程中断
1. interrupt()
方法
这是线程类提供的一个方法,作用是通知线程你“应该中断”了,但并不会强制结束线程。
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// do something
}
});
t.start();
t.interrupt(); // 通知中断
2. 检测中断状态的方式
Thread.currentThread().isInterrupted()
:检查是否被中断(不清除中断状态)Thread.interrupted()
:检查并清除中断状态(静态方法)
3. 中断阻塞线程(例如 sleep、wait、join)
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("线程被中断");
}
这些方法在收到中断信号时会抛出 InterruptedException
,这时应该合理处理(如清理资源或再次中断):
catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
}
- 如果线程在 sleep/wait 时被中断,会抛出
InterruptedException
; - 抛出异常之前,中断标志会被清除;
- 所以异常捕获后如果调用
isInterrupted()
,结果是false
。
线程通信
线程之间的通信是多线程编程中的核心问题,尤其是在涉及多个线程协作完成任务时。Java 提供了多种机制来实现线程通信,本质是让线程之间共享信息或协调运行顺序。
1.wait()
-
定义:
public final void wait()
(属于Object
类) -
作用: 当前线程进入等待状态,直到被其他线程
notify()
或notifyAll()
唤醒。 -
注意:
- 必须放在
synchronized
块或方法中。 - 调用后线程进入 WAITING 状态,并 释放锁。
- 必须放在
-
常见用法:
synchronized(obj) { while (!condition) { obj.wait(); // 线程等待 } }
2. notify()
/ notifyAll()
-
定义:
public final void notify()
(属于Object
类) -
作用:
- 唤醒一个或所有正在该对象上等待的线程。
- 不会立刻释放锁,线程只有等当前同步块执行完才会获取锁继续执行。
-
常见用法:
synchronized(obj) { obj.notify(); // 唤醒等待线程 }
3. join()
-
定义:
public final void join()
(属于Thread
类) -
作用: 当前线程等待目标线程执行完毕再继续执行。
-
不需要在 synchronized 中使用。
-
线程状态:
- 调用 join 的线程会进入
WAITING
或TIMED_WAITING
状态,直到被等待的线程终止。
- 调用 join 的线程会进入
-
常见用法:
Thread t = new Thread(() -> { doWork(); }); t.start(); t.join(); // 主线程等待子线程执行完毕