Skip to content

03_线程基础

目录

  1. 线程概述
  2. Thread 与 Runnable
  3. 线程生命周期与状态
  4. 线程同步机制
  5. synchronized 关键字详解
  6. volatile 关键字
  7. ThreadLocal
  8. 面试高频考点

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 的区别

对比项ThreadRunnable
实现方式继承 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()); // NEW

RUNNABLE(可运行状态)

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 线程结束,进入 WAITING

3. LockSupport.park()

java
LockSupport.park(); // 进入 WAITING 状态

TIME_WAITING(超时等待状态)

1. Thread.sleep()

java
Thread.sleep(1000); // 休眠 1 秒,进入 TIME_WAITING

2. 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();
// 任务执行完毕后,状态变为 TERMINATED

3.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

特性synchronizedReentrantLock
实现方式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 + StoreLoad

7. 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()
所属类ObjectThread
是否释放锁
使用范围同步代码块/方法任意位置
唤醒方式notify/notifyAll时间到达

考点二:synchronized 细节

Q: synchronized 的锁升级过程?

A: 无锁 → 偏向锁 → 轻量级锁 → 重量级锁

Q: 如何优化 synchronized 性能?

A:

  1. 减少锁粒度
  2. 使用锁对象代替 this
  3. 考虑使用 ReentrantLock
  4. 使用并发容器替代同步容器

考点三: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:

  1. 使用完毕后调用 remove()
  2. 使用 try-finally 确保清理
  3. 在线程池环境中特别注意清理

考点五:线程安全问题

Q: 如何保证线程安全?

A:

  1. 减少共享变量
  2. 使用不可变对象
  3. 使用同步机制(synchronized、Lock)
  4. 使用并发工具类
  5. 使用 ThreadLocal

考点六:守护线程

Q: 守护线程是什么?有什么特点?

A: 守护线程是为其他线程服务的后台线程,当所有用户线程结束时,守护线程自动终止。常见如 GC 线程。

Q: 如何创建守护线程?

A: 在 start() 之前调用 setDaemon(true)。

考点七:死锁

Q: 什么是死锁?如何避免?

A: 死锁是两个或多个线程互相等待对方释放资源而陷入永久阻塞。

避免方法:

  1. 统一加锁顺序
  2. 使用超时获取锁
  3. 避免嵌套锁
  4. 使用 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:

  1. 减少线程创建和销毁开销
  2. 控制并发数,防止系统过载
  3. 统一管理线程资源

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);

参考文献

  1. 《Java 并发编程实战》
  2. 《深入理解 Java 虚拟机》
  3. 《Android 高性能开发实践》
  4. JDK 官方文档

总结: 线程基础是 Android 开发的基石。掌握 Thread、线程状态、同步机制等核心概念,不仅能写出高性能代码,还能在面试中应对各种并发问题。建议结合实际项目经验,多动手实践,深入理解线程的本质。