Appearance
03_线程基础
目录
1. 线程概述
1.1 什么是线程
线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
在 Android 开发中,线程扮演着至关重要的角色:
- UI 线程(主线程):负责处理 UI 相关操作,如视图绘制、用户事件响应等
- 工作线程(子线程):负责执行耗时操作,如网络请求、数据库操作、文件读写等
1.2 为什么需要线程
避免 ANR(Application Not Responding):Android 主线程必须在 5 秒内响应事件,否则系统会弹出 ANR 对话框。通过线程将耗时操作移至后台,可以避免 ANR 问题。
提高应用性能:利用多核 CPU 并行处理任务,提升应用响应速度和用户体验。
实现并发操作:同时执行多个任务,如下载多个文件、同时请求多个接口等。
1.3 进程与线程的关系
进程 (Process)
├── 进程资源(内存空间、文件句柄等)
│
└── 线程 (Threads)
├── 主线程(UI 线程)
├── 工作线程 1
├── 工作线程 2
└── ...区别:
- 进程是资源分配的最小单位,线程是 CPU 调度的最小单位
- 一个进程可以包含多个线程,这些线程共享进程的资源
- 线程之间切换开销小,进程之间切换开销大
2. Thread 与 Runnable
2.1 创建线程的两种方式
方式一:继承 Thread 类
java
// 定义线程类
class MyThread extends Thread {
@Override
public void run() {
// 线程要执行的任务
Log.d("Thread", "线程执行中:" + Thread.currentThread().getName());
}
}
// 启动线程
MyThread thread = new MyThread();
thread.start(); // 调用 start() 方法启动线程方式二:实现 Runnable 接口
java
// 定义任务
Runnable task = new Runnable() {
@Override
public void run() {
Log.d("Runnable", "Runnable 任务执行中:" + Thread.currentThread().getName());
}
};
// 创建并启动线程
Thread thread = new Thread(task);
thread.start();方式三:Lambda 表达式(推荐)
java
// 使用 Lambda 简化代码
Thread thread = new Thread(() -> {
Log.d("Lambda", "Lambda 任务执行中:" + Thread.currentThread().getName());
});
thread.start();2.2 Thread 与 Runnable 的区别
| 对比项 | Thread | Runnable |
|---|---|---|
| 实现方式 | 继承 Thread 类 | 实现 Runnable 接口 |
| 扩展性 | 受限于 Java 单继承 | 可以继承其他类 |
| 资源共享 | 各自独立 | 可以共享数据 |
| 推荐程度 | 不推荐 | 推荐使用 |
| Java 8+ | - | 可用 Callable + Future |
2.3 Callable 与 Future(进阶)
Runnable 无法返回值,而 Callable 可以:
java
// 定义可返回结果的任務
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000); // 模拟耗时操作
return "任务完成,时间:" + System.currentTimeMillis();
}
};
// 使用 ExecutorService 执行
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(callable);
// 获取结果(阻塞)
try {
String result = future.get(); // 阻塞等待结果
Log.d("Callable", "结果:" + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();2.4 Thread 常用方法
java
public class ThreadMethods {
// 1. 获取线程名称
public void threadName() {
String name = Thread.currentThread().getName();
Log.d("Thread", "线程名:" + name);
}
// 2. 设置线程名称
public void setThreadName() {
Thread thread = new Thread(() -> {
// 线程执行内容
});
thread.setName("自定义线程名");
thread.start();
}
// 3. 获取线程优先级
public void threadPriority() {
int priority = Thread.currentThread().getPriority();
Log.d("Thread", "优先级:" + priority);
}
// 4. 设置线程优先级(1-10)
public void setPriority() {
Thread thread = new Thread(() -> {});
thread.setPriority(Thread.MIN_PRIORITY); // 1
thread.setPriority(Thread.MAX_PRIORITY); // 10
thread.setPriority(Thread.NORM_PRIORITY); // 5
}
// 5. 让出 CPU 时间片
public void yield() {
Thread.yield(); // 让当前线程让出 CPU,同优先级线程有机会执行
}
// 6. 暂停指定时间
public void sleep() {
Thread.sleep(1000); // 休眠 1 秒
}
// 7. 判断是否是守护线程
public void isDaemon() {
boolean daemon = Thread.currentThread().isDaemon();
Log.d("Thread", "守护线程:" + daemon);
}
// 8. 设置守护线程
public void setDaemon() {
Thread thread = new Thread(() -> {
while (true) {
// 守护线程任务
}
});
thread.setDaemon(true); // 必须在 start() 之前设置
}
// 9. 获取堆栈跟踪
public void stackTrace() {
Thread thread = Thread.currentThread();
StackTraceElement[] trace = thread.getStackTrace();
for (StackTraceElement element : trace) {
Log.d("Trace", element.toString());
}
}
}3. 线程生命周期与状态
3.1 六种线程状态(Thread.State)
Java 5 引入的线程状态枚举:
┌─────────────┐
│ NEW │ 新建:线程已创建,但未启动
└──────┬──────┘
│ start()
▼
┌─────────────┐
│ RUNNABLE │ 可运行:线程正在 JVM 中执行,等待 CPU 时间片
└──────┬──────┘
│
├────────────────────────────────────┐
│ sleep()/wait()/join() │
▼ │
┌─────────────┐ │
│ BLOCKED │ 阻塞:等待获取监视器锁 │
└──────┬──────┘ │
│ │
▼ ▼
┌─────────────┐
│ WAITING │ 等待:无限期等待其他线程通知
└──────┬──────┘
│
├────────────────────────────────────┐
│ timeout │
▼ │
┌─────────────┐ │
│ TIME_WAITING│ 超时等待:在指定时间内等待 │
└──────┬──────┘ │
│ │
▼ │
┌─────────────┐ │
│ TERMINATED│ 终止:线程执行完毕或异常退出 │
└─────────────┘ │3.2 各状态详解与示例
NEW(新建状态)
java
Thread thread = new Thread(() -> {
// 任务
});
// 此时线程状态为 NEW
System.out.println(thread.getState()); // NEWRUNNABLE(可运行状态)
java
thread.start(); // 调用 start() 后进入 RUNNABLE 状态
// 线程可能正在运行,也可能在等待 CPU 时间片BLOCKED(阻塞状态)
等待获取监视器锁时进入:
java
class BlockedExample {
private static final Object lock = new Object();
public void method1() {
synchronized (lock) {
synchronized (lock) {
// 尝试获取同一锁时进入 BLOCKED
}
}
}
}WAITING(等待状态)
1. Object.wait()
java
Object lock = new Object();
synchronized (lock) {
lock.wait(); // 进入 WAITING 状态
}2. Thread.join()
java
Thread t = new Thread(() -> {});
t.start();
t.join(); // 当前线程等待 t 线程结束,进入 WAITING3. LockSupport.park()
java
LockSupport.park(); // 进入 WAITING 状态TIME_WAITING(超时等待状态)
1. Thread.sleep()
java
Thread.sleep(1000); // 休眠 1 秒,进入 TIME_WAITING2. Object.wait(timeout)
java
synchronized (lock) {
lock.wait(1000); // 最多等待 1 秒
}3. Thread.join(timeout)
java
t.join(1000); // 最多等待 t 线程 1 秒4. LockSupport.parkNanos()
java
LockSupport.parkNanos(1_000_000_000L); // 等待 1 秒TERMINATED(终止状态)
java
Thread thread = new Thread(() -> {
// 任务执行
});
thread.start();
// 任务执行完毕后,状态变为 TERMINATED3.3 状态转换示例
java
public class StateTransition {
private static final Object lock = new Object();
public void demonstrateStates() throws InterruptedException {
Thread worker = new Thread(() -> {
System.out.println("RUNNABLE: " + Thread.currentThread().getState());
synchronized (lock) {
System.out.println("BLOCKED: " + Thread.currentThread().getState());
}
synchronized (lock) {
try {
lock.wait(1000); // TIME_WAITING
} catch (InterruptedException e) {}
System.out.println("TIME_WAITING: " + Thread.currentThread().getState());
}
synchronized (lock) {
try {
lock.wait(); // WAITING
} catch (InterruptedException e) {}
System.out.println("WAITING: " + Thread.currentThread().getState());
}
});
System.out.println("NEW: " + worker.getState());
worker.start();
worker.join();
System.out.println("TERMINATED: " + worker.getState());
}
}4. 线程同步机制
4.1 为什么要线程同步
问题场景:多线程共享数据导致的数据不一致
java
// ❌ 不安全的代码
class Counter {
private int count = 0;
public void increment() {
count++; // 非原子操作,多线程下会出错
}
public int getCount() {
return count;
}
}
// 测试
Counter counter = new Counter();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 10000; j++) {
counter.increment();
}
}).start();
}
// 结果通常小于 100000,因为存在竞争条件4.2 解决线程安全的方法
| 方法 | 描述 | 适用场景 |
|---|---|---|
| synchronized | 内置锁 | 简单场景 |
| Lock 接口 | 显式锁 | 需要更灵活控制 |
| volatile | 保证可见性 | 状态标志 |
| Atomic 类 | 原子操作 | 计数器、原子变量 |
| ConcurrentHashMap | 并发容器 | 高并发场景 |
| ThreadLocal | 线程隔离 | 每个线程独立数据 |
4.3 线程通信
Object 类的 wait/notify 机制:
java
class ProducerConsumer {
private final Queue<Integer> queue = new LinkedList<>();
private final int MAX_SIZE = 10;
private final Object lock = new Object();
// 生产者
public void produce() throws InterruptedException {
synchronized (lock) {
while (queue.size() >= MAX_SIZE) {
lock.wait(); // 队列满,等待
}
queue.add(new Integer(System.currentTimeMillis()));
lock.notifyAll(); // 通知消费者
}
}
// 消费者
public void consume() throws InterruptedException {
synchronized (lock) {
while (queue.isEmpty()) {
lock.wait(); // 队列空,等待
}
Integer value = queue.poll();
System.out.println("消费:" + value);
lock.notifyAll(); // 通知生产者
}
}
}4.4 生产者 - 消费者模式完整示例
java
public class ProducerConsumerExample {
static class Buffer {
private final List<Integer> data = new ArrayList<>();
private final int capacity;
public Buffer(int capacity) {
this.capacity = capacity;
}
public synchronized void produce(int item) throws InterruptedException {
while (data.size() == capacity) {
wait(); // 缓冲区满,等待
}
data.add(item);
System.out.println("生产:" + item + ", 当前:" + data.size());
notifyAll(); // 通知消费者
}
public synchronized int consume() throws InterruptedException {
while (data.isEmpty()) {
wait(); // 缓冲区空,等待
}
int item = data.remove(0);
System.out.println("消费:" + item + ", 当前:" + data.size());
notifyAll(); // 通知生产者
return item;
}
}
public static void main(String[] args) {
Buffer buffer = new Buffer(5);
// 生产者线程
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
buffer.produce(i);
Thread.sleep(100);
}
} catch (InterruptedException e) {}
}).start();
// 消费者线程
new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
buffer.consume();
Thread.sleep(150);
}
} catch (InterruptedException e) {}
}).start();
}
}4.5 并发工具类(Java 5+)
CountDownLatch(倒数门闩):
java
// 主线程等待多个任务完成
CountDownLatch latch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
// 执行任务
latch.countDown(); // 完成任务,计数减一
}).start();
}
latch.await(); // 等待所有任务完成
System.out.println("所有任务完成");CyclicBarrier(循环屏障):
java
// 多个线程互相等待
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
// 所有线程到达后执行
System.out.println("所有线程到达屏障");
});
for (int i = 0; i < 3; i++) {
final int threadNum = i;
new Thread(() -> {
try {
Thread.sleep((long)(Math.random() * 1000));
System.out.println("线程" + threadNum + "到达屏障");
barrier.await();
System.out.println("线程" + threadNum + "继续执行");
} catch (Exception e) {}
}).start();
}Semaphore(信号量):
java
// 控制同时访问资源的线程数
Semaphore semaphore = new Semaphore(3); // 最多 3 个线程
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可
// 访问共享资源
semaphore.release(); // 释放许可
} catch (InterruptedException e) {}
}).start();
}5. synchronized 关键字详解
5.1 三种使用方式
1. 修饰实例方法(锁住当前对象实例)
java
class Counter {
private int count = 0;
// 锁住的是 this
public synchronized void increment() {
count++;
}
}2. 修饰静态方法(锁住 Class 对象)
java
class Counter {
private static int count = 0;
// 锁住的是 Counter.class
public static synchronized void increment() {
count++;
}
}3. 修饰代码块(锁住指定对象)
java
class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
// 锁住的是 lock 对象
synchronized (lock) {
count++;
}
}
// 锁住 this
synchronized (this) {
count++;
}
}5.2 synchronized 源码层面
JVM 实现:监视器锁(Monitor)
Monitor {
Object owner; // 锁的持有者
int lockCount; // 锁重入次数
EntrySet entries; // 等待获取锁的线程队列
ObjectWaitSet waitSet; // 调用 wait() 的线程队列
}5.3 synchronized 锁升级过程(JDK 1.6+)
┌──────────────┐
│ 无锁 │ 对象未被任何线程锁定
└──────┬───────┘
│ 第一个线程加锁
▼
┌──────────────┐
│ 偏向锁 │ 锁偏向第一个获得它的线程
└──────┬───────┘
│ 另一个线程尝试获取
▼
┌──────────────┐
│ 轻量级锁 │ 自旋锁,无阻塞,适用于竞争不激烈的场景
└──────┬───────┘
│ 自旋失败或存在阻塞
▼
┌──────────────┐
│ 重量级锁 │ 使用 OS 的 Mutex,线程阻塞等待
└──────────────┘5.4 锁重入(可重入锁)
synchronized 是可重入锁,同一线程可以多次获取同一把锁:
java
class ReentrantLock {
public synchronized void method1() {
System.out.println("method1");
method2(); // 可以递归调用
}
public synchronized void method2() {
System.out.println("method2");
}
}5.5 synchronized 性能优化
1. 减少锁粒度
java
// ❌ 不推荐:锁住整个方法
public synchronized void process() {
// 很多不需要同步的代码
// ...
// 只有少部分需要同步
// ...
}
// ✅ 推荐:只锁关键代码
public void process() {
// 不需要同步的代码
// ...
synchronized (lock) {
// 需要同步的代码
}
// 不需要同步的代码
// ...
}2. 使用 Lock 对象代替 this
java
class BetterLock {
private final Object lock = new Object();
public void process() {
synchronized (lock) {
// 使用私有锁对象,避免外部恶意代码获取同一锁
}
}
}3. 锁粗化
JVM 会自动将多个连续的 synchronized 合并为一个:
java
// JVM 优化:两个锁会合并
synchronized (lock) {
// 操作
}
synchronized (lock) {
// 操作
}5.6 synchronized vs ReentrantLock
| 特性 | synchronized | ReentrantLock |
|---|---|---|
| 实现方式 | JVM 内置 | JDK API |
| 锁释放 | 自动 | 手动 (unlock) |
| 可中断 | 否 | 是 (tryLock) |
| 公平锁 | 否 | 可选 |
| 条件变量 | 一个 | 多个 |
| 性能 | JDK 1.6+ 接近 | 高竞争下稍优 |
java
// ReentrantLock 示例
class LockExample {
private final ReentrantLock lock = new ReentrantLock();
public void process() {
lock.lock();
try {
// 临界区代码
} finally {
lock.unlock(); // 必须释放
}
}
// 带超时的锁
public boolean tryProcess() {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
// 临界区代码
return true;
} finally {
lock.unlock();
}
}
return false;
}
// 公平锁
private final ReentrantLock fairLock = new ReentrantLock(true);
}6. volatile 关键字
6.1 volatile 的作用
1. 保证可见性
当一个线程修改了 volatile 变量的值,新值对于其他线程立即可见:
java
class VolatileExample {
private volatile boolean running = true;
public void start() {
while (running) {
// 工作线程,能立即看到 running 的变化
}
}
public void stop() {
running = false; // 修改后,start() 中的线程立即可见
}
}2. 禁止指令重排序
volatile 保证操作不会被编译器或处理器重排序:
java
class DoubleCheckLock {
private volatile static Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); // 禁止重排序
}
}
}
return instance;
}
}6.2 volatile 不能保证原子性
java
class VolatileAtomic {
private volatile int count = 0;
public void increment() {
count++; // ❌ 非原子操作,volatile 无法保证
}
}
// ✅ 正确做法:使用 AtomicInteger
class AtomicExample {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // 原子操作
}
}6.3 volatile 使用场景
1. 状态标志
java
class StopFlag {
private volatile boolean stop = false;
public void run() {
while (!stop) {
// 执行任务
}
}
public void stop() {
stop = true;
}
}2. 发布机制(Publish)
java
class Publisher {
private volatile Object data;
public void publish() {
// 初始化 data
data = new Object();
// 其他线程立即可见
}
}6.4 volatile 底层实现
内存屏障(Memory Barrier):
// 编译时屏障
StoreStore Barrier
LoadLoad Barrier
StoreLoad Barrier
LoadStore Barrier
// volatile 读:LoadLoad + LoadStore
// volatile 写:StoreStore + StoreLoad7. ThreadLocal
7.1 什么是 ThreadLocal
ThreadLocal 为每个线程提供一个独立的变量副本,实现线程隔离:
java
class ThreadLocalExample {
private static ThreadLocal<String> local = ThreadLocal.withInitial(() -> "初始值");
public void test() {
// 每个线程看到不同的值
local.set("线程值");
System.out.println(local.get());
}
}7.2 工作原理
ThreadLocalMap {
Entry[] table; // 每个线程一个 map
class Entry extends WeakReference<ThreadLocal<?>> {
Object value; // 变量值
}
}7.3 典型使用场景
1. 数据库连接管理
java
class DbConnectionManager {
private static ThreadLocal<Connection> connectionHolder =
ThreadLocal.withInitial(() -> {
// 创建数据库连接
return DriverManager.getConnection(url, user, password);
});
public static Connection getConnection() {
return connectionHolder.get();
}
public static void closeConnection() {
connectionHolder.get().close();
connectionHolder.remove(); // 防止内存泄漏
}
}2. 用户上下文管理
java
class UserContext {
private static ThreadLocal<User> userHolder = new ThreadLocal<>();
public static void setUser(User user) {
userHolder.set(user);
}
public static User getUser() {
return userHolder.get();
}
public static void clear() {
userHolder.remove(); // 清理
}
}7.4 内存泄漏问题
ThreadLocal 存在内存泄漏风险,必须手动调用 remove():
java
// ❌ 不推荐
static ThreadLocal<String> local = new ThreadLocal<>();
// ✅ 推荐
static ThreadLocal<String> local = new ThreadLocal<>() {
protected Object initialValue() {
return "";
}
protected void finalize() {
remove();
}
};
// ✅ 最佳实践
try {
local.set("value");
// 使用 local.get()
} finally {
local.remove(); // 手动清理
}7.5 InheritableThreadLocal
java
class ParentThread extends Thread {
private static InheritableThreadLocal<String> local =
new InheritableThreadLocal<>();
@Override
public void run() {
local.set("父线程值");
Thread child = new Thread(() -> {
// 子线程自动继承父线程的 ThreadLocal 值
System.out.println(local.get()); // "父线程值"
});
child.start();
}
}8. 面试高频考点
考点一:线程状态转换
Q: 线程从 RUNNABLE 到 BLOCKED 需要什么条件?
A: 当线程尝试获取监视器锁,而该锁已被其他线程持有时,进入 BLOCKED 状态。
Q: wait() 和 sleep() 的区别?
| 区别 | wait() | sleep() |
|---|---|---|
| 所属类 | Object | Thread |
| 是否释放锁 | 是 | 否 |
| 使用范围 | 同步代码块/方法 | 任意位置 |
| 唤醒方式 | notify/notifyAll | 时间到达 |
考点二:synchronized 细节
Q: synchronized 的锁升级过程?
A: 无锁 → 偏向锁 → 轻量级锁 → 重量级锁
Q: 如何优化 synchronized 性能?
A:
- 减少锁粒度
- 使用锁对象代替 this
- 考虑使用 ReentrantLock
- 使用并发容器替代同步容器
考点三:volatile 理解
Q: volatile 能实现原子性吗?
A: 不能。volatile 只保证可见性和有序性,不能保证原子性。
Q: volatile 和 synchronized 的区别?
A:
- volatile 是变量修饰符,synchronized 可以修饰方法或代码块
- volatile 不阻塞线程,synchronized 会阻塞
- volatile 不能保证原子性,synchronized 可以
考点四:ThreadLocal 内存泄漏
Q: ThreadLocal 为什么会内存泄漏?
A: Entry 的 key 是 ThreadLocal 的弱引用,但 value 是强引用。如果不清理,value 无法被回收。
Q: 如何避免 ThreadLocal 内存泄漏?
A:
- 使用完毕后调用 remove()
- 使用 try-finally 确保清理
- 在线程池环境中特别注意清理
考点五:线程安全问题
Q: 如何保证线程安全?
A:
- 减少共享变量
- 使用不可变对象
- 使用同步机制(synchronized、Lock)
- 使用并发工具类
- 使用 ThreadLocal
考点六:守护线程
Q: 守护线程是什么?有什么特点?
A: 守护线程是为其他线程服务的后台线程,当所有用户线程结束时,守护线程自动终止。常见如 GC 线程。
Q: 如何创建守护线程?
A: 在 start() 之前调用 setDaemon(true)。
考点七:死锁
Q: 什么是死锁?如何避免?
A: 死锁是两个或多个线程互相等待对方释放资源而陷入永久阻塞。
避免方法:
- 统一加锁顺序
- 使用超时获取锁
- 避免嵌套锁
- 使用 tryLock
java
// 死锁示例
class Deadlock {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void thread1() {
synchronized (lock1) {
Thread.sleep(100);
synchronized (lock2) {
// 死锁
}
}
}
public void thread2() {
synchronized (lock2) {
Thread.sleep(100);
synchronized (lock1) {
// 死锁
}
}
}
}考点八:上下文切换
Q: 什么是上下文切换?
A: 线程切换时,保存当前线程的上下文(寄存器、程序计数器等),恢复下一个线程的上下文。过多切换会影响性能。
考点九:线程池参数
Q: 为什么需要线程池?
A:
- 减少线程创建和销毁开销
- 控制并发数,防止系统过载
- 统一管理线程资源
Q: 线程池核心参数有哪些?
A:
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:空闲线程存活时间
- workQueue:任务队列
- threadFactory:线程工厂
- handler:拒绝策略
考点十:Thread vs Runnable vs Callable
Q: 三者的区别?
A:
- Thread:继承类,无法返回值
- Runnable:接口,可以返回值,推荐使用
- Callable:接口,可以返回值和抛出异常,配合 Future 使用
最佳实践总结
1. 线程命名规范
java
// 推荐:使用自定义线程名,便于调试
Thread thread = new Thread(() -> {
// 任务
}, "MyCustomThread-" + index);2. 异常处理
java
// 推荐:在线程中捕获异常并处理
new Thread(() -> {
try {
// 任务
} catch (Exception e) {
// 处理异常,避免线程静默退出
e.printStackTrace();
}
}).start();3. 避免频繁创建线程
java
// ❌ 不推荐:频繁创建销毁线程
for (int i = 0; i < 100; i++) {
new Thread(task).start();
}
// ✅ 推荐:使用线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executor.submit(task);
}
executor.shutdown();4. 优先使用并发工具类
java
// ✅ 推荐使用 JUC 工具类
CountDownLatch latch = new CountDownLatch(n);
CyclicBarrier barrier = new CyclicBarrier(n);
Semaphore semaphore = new Semaphore(n);参考文献
- 《Java 并发编程实战》
- 《深入理解 Java 虚拟机》
- 《Android 高性能开发实践》
- JDK 官方文档
总结: 线程基础是 Android 开发的基石。掌握 Thread、线程状态、同步机制等核心概念,不仅能写出高性能代码,还能在面试中应对各种并发问题。建议结合实际项目经验,多动手实践,深入理解线程的本质。