多线程基础
一、线程启动方式(4种)
1. 继承 Thread
类(基础方式)
- 步骤:
- 自定义类继承
Thread
,重写run()
方法(线程执行体)。 - 创建子类实例,调用
start()
方法启动线程。
- 自定义类继承
- 示例:
public class MyThread extends Thread { @Override public void run() { System.out.println("线程 " + getName() + " 启动"); } } // 启动 new MyThread().start();
- 特点:
- 子类化
Thread
,耦合度高(Java 单继承限制),不推荐用于资源共享场景。
- 子类化
2. 实现 Runnable
接口(推荐)
- 步骤:
- 自定义类实现
Runnable
,重写run()
方法。 - 创建
Runnable
实例,作为参数传入Thread
构造器,调用start()
。
- 自定义类实现
- 示例:
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("Runnable 线程启动"); } } // 启动 new Thread(new MyRunnable()).start();
- 特点:
- 解耦线程与任务(线程是执行载体,任务是具体逻辑),支持资源共享(多个线程可共享同一个
Runnable
实例)。
- 解耦线程与任务(线程是执行载体,任务是具体逻辑),支持资源共享(多个线程可共享同一个
3. 使用 Callable
+ Future
(带返回值)
- 步骤:
- 自定义类实现
Callable<V>
,重写call()
方法(可抛出异常,有返回值)。 - 通过
FutureTask
包装Callable
,传入Thread
启动,或通过ExecutorService
提交。
- 自定义类实现
- 示例:
import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { return 1 + 2; // 返回计算结果 } } // 启动 FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable()); new Thread(futureTask).start(); Integer result = futureTask.get(); // 获取返回值(阻塞直到结果可用)
- 特点:
- 支持返回值和异常处理,适合需要线程执行结果的场景。
4. 使用线程池(ExecutorService
,推荐)
- 步骤:
- 通过
Executors
工具类创建线程池(如newFixedThreadPool
)。 - 提交任务(
Runnable
或Callable
)到线程池,由池管理线程生命周期。
- 通过
- 示例:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; ExecutorService executor = Executors.newFixedThreadPool(5); executor.submit(new MyRunnable()); // 提交 Runnable 任务 executor.submit(new MyCallable()); // 提交 Callable 任务 executor.shutdown(); // 关闭线程池
- 特点:
- 复用线程,减少创建/销毁开销,控制并发数量,适合高并发场景。
二、Thread
类常用方法
1. 线程控制方法
start() |
启动线程(进入就绪状态,等待 CPU 调度) | 实例方法 |
run() |
线程执行体(子类重写,默认无操作) | 实例方法 |
join() |
等待当前线程结束后,主线程再继续执行(可传超时参数) | 实例方法 |
sleep(long ms) |
让线程睡眠指定毫秒,释放 CPU 时间片(不会释放锁) | 静态方法 |
yield() |
提示线程让出 CPU(建议性,不一定生效) | 静态方法 |
isAlive() |
判断线程是否处于活动状态(已启动且未终止) | 实例方法 |
setDaemon(boolean on) |
设置为守护线程(如垃圾回收线程,主线程结束则守护线程自动终止) | 实例方法 |
2. 线程状态相关
getState()
:获取线程状态(NEW
/RUNNABLE
/BLOCKED
/WAITING
/TIMED_WAITING
/TERMINATED
)。interrupt()
:中断线程(设置中断标志,不直接终止线程)。
三、线程交互(线程间通信)
1. wait()
/notify()
/notifyAll()
- 作用:实现线程间的协作(如生产者-消费者模型),需配合
synchronized
使用。 - 规则:
- 只能在 同步块(
synchronized
) 中调用。 wait()
:当前线程释放锁,进入等待队列,直到被notify()
/notifyAll()
唤醒。notify()
:唤醒等待队列中的一个线程;notifyAll()
:唤醒所有等待线程。
- 只能在 同步块(
- 示例(生产者-消费者):
public class ProducerConsumer { private static final Object lock = new Object(); private static int count = 0; // 生产者 public static class Producer implements Runnable { @Override public void run() { synchronized (lock) { while (count >= 1) { // 避免虚假唤醒,用 while 而非 if try { lock.wait(); // 等待消费者处理 } catch (InterruptedException e) { e.printStackTrace(); } } count++; System.out.println("生产后 count = " + count); lock.notifyAll(); // 唤醒消费者 } } } // 消费者 public static class Consumer implements Runnable { @Override public void run() { synchronized (lock) { while (count <= 0) { try { lock.wait(); // 等待生产者生产 } catch (InterruptedException e) { e.printStackTrace(); } } count--; System.out.println("消费后 count = " + count); lock.notifyAll(); // 唤醒生产者 } } } }
2. CountDownLatch
/CyclicBarrier
(并发工具类)
CountDownLatch
:多个线程等待某个事件完成(如主线程等待所有子线程结束)。CyclicBarrier
:多个线程相互等待,到达某个屏障点后一起执行。
四、线程中断机制
1. 中断标志(Interrupt Flag)
- 每个线程有一个 中断标志位(布尔值),默认
false
。 interrupt()
:调用后设置标志为true
,不直接终止线程。
2. 检测中断的方式
isInterrupted() |
获取当前线程的中断标志(不会清除标志) |
interrupted() |
获取当前线程的中断标志,并清除标志(静态方法,通常在 catch 中使用) |
3. 处理中断的场景
-
场景 1:线程处于阻塞状态(如
sleep
/join
/wait
)- 调用
interrupt()
会抛出InterruptedException
,需在catch
中处理(清除标志为false
)。
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 重新设置中断标志,传递给上层 e.printStackTrace(); }
- 调用
-
场景 2:线程在运行中(非阻塞)
- 手动检测中断标志,主动终止逻辑。
while (!Thread.currentThread().isInterrupted()) { // 正常业务逻辑 } System.out.println("线程被中断,结束运行");
4. 注意事项
- 中断机制是 协作式 的,线程需自行处理中断标志,无法强制终止线程(
stop()
已过时,可能导致资源泄漏)。 - 守护线程(
setDaemon(true)
)会随主线程结束而终止,无需手动中断。
总结
- 线程启动:
Runnable
和线程池是主流,支持解耦和资源共享;Callable
用于需要返回值的场景。 - 线程交互:
wait
/notify
是基础,结合synchronized
实现协作;并发工具类(如CountDownLatch
)简化复杂场景。 - 中断机制:通过设置中断标志通知线程终止,需结合业务逻辑处理,避免强制终止。
JUC编程 文章被收录于专栏
JUC 是 Java.util.concurrent 包的简称,它是 Java 5 引入的一个用于处理并发编程的工具包,为 Java 开发者提供了一系列用于高效处理并发任务的类和接口,极大地简化了多线程编程的复杂性。