多线程及其声明周期
多线程
- 多线程 是指在一个进程中同时运行多个线程,每个线程执行不同的任务
- 在多线程中,主线程也是一个单独的线程,主线程结束其他线程仍然会继续执行
实现方式
-
继承 Thread 类,通过继承 Thread 类并重写 run() 方法来实现多线程
- 简单易用,适合简单的多线程任务
- 由于 Java 是单继承,继承 Thread 类会限制类的扩展性
class MyThread extends Thread { @Override public void run() { System.out.println("Thread is running: " + Thread.currentThread().getName()); } } public class ThreadExample { public static void main(String[] args) { MyThread thread1 = new MyThread(); MyThread thread2 = new MyThread(); thread1.start(); // 启动线程 thread2.start(); } } -
实现 Runnable 接口,通过实现 Runnable 接口并实现 run() 方法来实现多线程
-
更灵活,适合需要扩展其他类的情况
-
推荐使用,因为 Java 支持多接口实现
-
需要用Thread类包裹,因为只有Thread类中存在start()方法
class MyRunnable implements Runnable { @Override public void run() { System.out.println("Thread is running: " + Thread.currentThread().getName()); } } public class RunnableExample { public static void main(String[] args) { Thread thread1 = new Thread(new MyRunnable()); Thread thread2 = new Thread(new MyRunnable()); thread1.start(); // 启动线程 thread2.start(); } }
-
-
实现 Callable 接口
-
通过实现 Callable 接口并实现 call() 方法来实现多线程。Callable 接口允许线程返回结果并抛出异常
-
允许线程返回结果
-
可以抛出异常,适合需要处理异常的场景。因为Callable 中的方法抛出了Exception异常而Runnable中的没有,所以Callable 的实现类可以抛出任意异常而Runnable子类只能抛出运行时异常
-
Future.get() 方法会阻塞当前线程,直到任务完成并返回结果
-
可以通过 Future.isDone() 检查任务是否完成
-
为了避免 Future.get() 无限期阻塞当前线程,可以设置超时时间。如果任务在指定时间内未完成,Future.get() 会抛出 TimeoutException
import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; class MyCallable implements Callable<String> { @Override public String call() throws Exception { return "Thread is running: " + Thread.currentThread().getName(); } } /* FutureTask 是 Future 接口的一个实现类,同时实现了 Runnable 接口。它可以直接包装 Callable 任务,并通过 Thread 或线程池执行 */ public class CallableExample { public static void main(String[] args) throws Exception { FutureTask<String> futureTask = new FutureTask<>(new MyCallable()); Thread thread = new Thread(futureTask); thread.start(); // 启动线程 System.out.println(futureTask.get()); // 获取线程返回值 } }第二种方式,通过线程池执行Callable接口对象行为,直接返回保存结果的Future对象
import java.util.concurrent.*; public class CallableExample { public static void main(String[] args) throws Exception { // 创建线程池 ExecutorService executor = Executors.newSingleThreadExecutor(); // 提交 Callable 任务 Future<String> future = executor.submit(new Callable<String>() { @Override public String call() throws Exception { return "Task is completed!"; } }); // 获取任务结果 String result = future.get(); System.out.println(result); // 输出: Task is completed! // 关闭线程池 executor.shutdown(); } }
-
-
使用线程池
-
通过线程池管理多个线程,避免频繁创建和销毁线程的开销
-
线程池中可以接收 Runnable 或 Callable 对象,因为Thread 实现了 Runnable 接口,所以executor.submit(thread) 可以使用,但这是 不推荐 的用法
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(2); // 创建线程池 executor.submit(() -> { System.out.println("Task 1 is running: " + Thread.currentThread().getName()); }); executor.submit(() -> { System.out.println("Task 2 is running: " + Thread.currentThread().getName()); }); executor.shutdown(); // 关闭线程池 } }
-
线程的生命周期
Java 中的线程生命周期包括以下7中,用Thread.State枚举表示了线程的几种状态
- 新建(New)
- 就绪(Runnable)
- 运行(Running)
- 阻塞(Blocked)
- 等待(Waiting)
- 超时等待(Timed Waiting)
- 终止(Terminated)
可以通过 Thread.getState() 方法获取线程的当前状态
-
新建
- 定义:线程对象被创建,但尚未启动
- 触发条件:通过 new Thread() 创建线程对象
- 状态转换:调用 start() 方法后,线程进入 就绪(Runnable) 状态
-
就绪
- 定义:线程已经启动,等待 CPU 调度执行
- 触发条件:调用 start() 方法后,线程进入就绪状态
- 状态转换:
- 当线程获得 CPU 时间片时,进入 运行(Running) 状态
- 如果线程被阻塞或等待,进入 阻塞(Blocked) 或 等待(Waiting) 状态
-
运行
- 定义:线程正在执行任务
- 触发条件:线程获得 CPU 时间片
- 状态转换
- 当线程的时间片用完或主动让出 CPU 时,回到 就绪(Runnable) 状态
- 如果线程被阻塞或等待,进入 阻塞(Blocked) 或 等待(Waiting) 状态
- 当任务执行完毕时,进入 终止(Terminated) 状态
-
阻塞
- 定义:线程因等待锁或其他资源而暂停执行
- 触发条件
- 线程尝试获取一个被其他线程持有的锁
- 线程等待 I/O 操作完成
- 状态转换
- 当线程获得锁或资源时,回到 就绪(Runnable) 状态
-
等待
- 定义:线程因等待其他线程的通知而暂停执行
- 触发条件
- 调用 Object.wait() 方法
- 调用 Object.join() 方法(不带超时参数)
- 状态转换
- 当其他线程调用 notify() 或 notifyAll() 时,线程回到 就绪(Runnable) 状态
-
超时等待
-
线程因等待其他线程的通知或超时而暂停执行
-
触发条件
-
调用 Thread.sleep(long millis) 方法
- 让当前线程暂停执行指定的时间(毫秒)
- 不释放锁:sleep() 方法不会释放当前线程持有的锁
- 静态方法:sleep() 是 Thread 类的静态方法,作用于当前线程
- 可中断:sleep() 方法可能会被中断,抛出 InterruptedException
-
调用 Object.wait(long timeout) 方法
- 让当前线程暂停执行,并释放对象的锁,直到以下条件之一发生
- 其他线程调用该对象的 notify() 或 notifyAll() 方法
- 指定的超时时间到达
- 释放锁:wait() 方法会释放当前线程持有的对象锁
- 必须在同步块中调用:wait() 方法必须在 synchronized 块或方法中调用,否则会抛出 IllegalMonitorStateException
- 可中断:wait() 方法可能会被中断,抛出 InterruptedException
- 如果 wait() 方法被中断,线程会从 wait() 方法返回,并尝试重新获取锁
- 如果锁可用,线程会成功获取锁,并继续执行 wait() 之后的代码
- 如果锁被其他线程持有,线程会进入 阻塞(Blocked) 状态,等待锁的释放
public class WaitExample { private static final Object lock = new Object(); public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { synchronized (lock) { try { System.out.println("Thread is waiting..."); lock.wait(2000); // 等待 2 秒或被唤醒 System.out.println("Thread is awake!"); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); Thread.sleep(1000); // 主线程等待 1 秒 synchronized (lock) { lock.notify(); // 唤醒等待的线程 } } } - 让当前线程暂停执行,并释放对象的锁,直到以下条件之一发生
-
调用 Object.join(long millis) 方法
-
-
状态转换
- 当等待时间到达或收到通知时,线程回到 就绪(Runnable) 状态
-
-
终止
- 定义:线程执行完毕或被强制终止
- 触发条件
- 线程的 run() 方法执行完毕
- 线程被强制终止(如调用 stop() 方法,但不推荐使用)
- 状态转换
- 线程终止后无法再回到其他状态

浙公网安备 33010602011771号