1. 为什么我们需要Thread类
在Java的世界里,Thread类就像是一位经验丰富的交通警察,指挥着程序中的各种任务有序运行。想象一下,当你打开一个音乐播放器时,它需要同时处理播放音乐、显示歌词、下载歌曲封面等多件事情。如果没有多线程,这些任务只能一个接一个地执行,你的播放器就会像卡顿的老式录音机一样令人抓狂。
Thread类位于java.lang包中,是Java实现多线程编程的核心类。它提供了一种轻量级的执行单元,允许我们在单个程序中同时运行多个任务。与重量级的进程相比,线程共享相同的内存空间,创建和切换的开销要小得多。
注意:虽然线程比进程轻量,但创建过多线程仍会导致性能问题。每个线程都需要分配栈空间(默认512KB-1MB),大量线程会消耗可观的内存资源。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Thread类的核心构造与生命周期
2.1 创建线程的两种经典方式
第一种方式是直接继承Thread类。这就像定制一辆专属赛车 - 你可以完全按照自己的需求来设计:
java复制class MyThread extends Thread {
@Override
public void run() {
System.out.println("我的线程正在执行: " + getName());
}
}
// 使用方式
MyThread thread = new MyThread();
thread.start();
第二种方式是实现Runnable接口。这更像是租用标准赛车 - 更灵活且符合面向对象设计原则:
java复制class MyTask implements Runnable {
@Override
public void run() {
System.out.println("任务正在执行: " + Thread.currentThread().getName());
}
}
// 使用方式
Thread thread = new Thread(new MyTask());
thread.start();
实际开发中更推荐实现Runnable接口,因为Java不支持多重继承,使用接口可以保持扩展性。
2.2 线程生命周期的五个阶段
线程的一生就像人的成长历程,会经历不同的状态:
- 新建(NEW):线程对象刚被创建,但还没调用start()
- 就绪(RUNNABLE):调用start()后,等待CPU调度
- 运行(RUNNING):获得CPU时间片,执行run()方法
- 阻塞(BLOCKED):等待锁、I/O操作或调用sleep()等
- 终止(TERMINATED):run()执行完毕或发生未捕获异常
java复制Thread thread = new Thread(() -> {
try {
Thread.sleep(1000); // 进入TIMED_WAITING状态
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(thread.getState()); // NEW
thread.start();
System.out.println(thread.getState()); // RUNNABLE
3. 线程控制与调度技巧
3.1 精细控制线程执行
Thread类提供了多种方法来控制线程执行:
- join():等待线程执行完毕
java复制Thread t1 = new Thread(task1);
Thread t2 = new Thread(task2);
t1.start();
t1.join(); // 主线程等待t1完成
t2.start();
- sleep():让当前线程暂停指定时间
java复制try {
Thread.sleep(1000); // 暂停1秒
} catch (InterruptedException e) {
// 处理中断异常
}
- yield():提示调度器当前线程愿意让出CPU
java复制Thread.yield(); // 不保证立即生效
3.2 线程优先级与守护线程
每个线程都有优先级(1-10),默认是5。优先级高的线程获得更多CPU时间,但不保证绝对顺序:
java复制thread.setPriority(Thread.MAX_PRIORITY); // 10
守护线程(Daemon)是为其他线程提供服务的后台线程,当所有非守护线程结束时,JVM会自动退出:
java复制Thread daemonThread = new Thread(backgroundTask);
daemonThread.setDaemon(true);
daemonThread.start();
4. 线程安全与同步机制
4.1 竞态条件与数据不一致
当多个线程同时访问共享资源时,可能会出现竞态条件:
java复制class Counter {
private int count = 0;
public void increment() {
count++; // 非原子操作
}
}
4.2 同步解决方案
synchronized关键字:内置锁机制
java复制public synchronized void increment() {
count++;
}
或者使用同步代码块:
java复制public void increment() {
synchronized(this) {
count++;
}
}
volatile关键字:保证可见性但不保证原子性
java复制private volatile boolean running = true;
原子类:更高效的原子操作
java复制AtomicInteger atomicCount = new AtomicInteger(0);
atomicCount.incrementAndGet();
5. 现代并发工具与最佳实践
5.1 线程池替代裸线程
直接创建线程代价高昂,推荐使用线程池:
java复制ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> System.out.println("任务执行"));
executor.shutdown();
5.2 ThreadLocal的使用场景
ThreadLocal为每个线程提供独立的变量副本:
java复制ThreadLocal<SimpleDateFormat> dateFormat =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
String date = dateFormat.get().format(new Date());
5.3 Java虚拟线程(Loom项目)
Java 19引入了轻量级的虚拟线程:
java复制Thread virtualThread = Thread.startVirtualThread(() -> {
System.out.println("运行在虚拟线程中");
});
6. 常见陷阱与性能调优
6.1 死锁的产生与避免
死锁的四个必要条件:
- 互斥条件
- 请求与保持
- 不剥夺条件
- 循环等待
避免策略:
- 按固定顺序获取锁
- 使用tryLock()设置超时
- 减少同步范围
6.2 上下文切换开销
线程数不是越多越好,通常推荐:
java复制int optimalThreadCount = Runtime.getRuntime().availableProcessors() * (1 + 等待时间/计算时间);
6.3 线程转储分析
使用jstack或VisualVM分析线程状态:
bash复制jstack <pid> > thread_dump.txt
7. 实战案例:多线程下载管理器
让我们实现一个简单的多线程下载器:
java复制public class Downloader {
private final ExecutorService executor;
private final int threadCount;
public Downloader(int threadCount) {
this.threadCount = threadCount;
this.executor = Executors.newFixedThreadPool(threadCount);
}
public void download(String url, String savePath) {
long fileSize = getFileSize(url);
long chunkSize = fileSize / threadCount;
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < threadCount; i++) {
long start = i * chunkSize;
long end = (i == threadCount - 1) ? fileSize : start + chunkSize - 1;
futures.add(executor.submit(() -> {
downloadChunk(url, savePath, start, end);
}));
}
// 等待所有任务完成
for (Future<?> future : futures) {
try {
future.get();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 其他辅助方法...
}
在这个实现中,我们:
- 根据CPU核心数创建线程池
- 将大文件分割成多个块
- 每个线程负责下载一个块
- 使用Future等待所有下载完成
- 最后合并所有块
8. 调试与性能监控技巧
8.1 线程命名的重要性
给线程起有意义的名字便于调试:
java复制Thread worker = new Thread(task, "File-Processor-Thread");
8.2 使用ThreadMXBean监控
获取线程信息:
java复制ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
long[] threadIds = threadMXBean.getAllThreadIds();
for (long id : threadIds) {
ThreadInfo info = threadMXBean.getThreadInfo(id);
System.out.println(info.getThreadName() + ": " + info.getThreadState());
}
8.3 异步日志记录
避免同步日志造成的性能瓶颈:
java复制private final ExecutorService logExecutor = Executors.newSingleThreadExecutor();
public void logAsync(String message) {
logExecutor.submit(() -> logger.info(message));
}
9. 线程中断的正确处理方式
9.1 响应中断的最佳实践
正确处理InterruptedException:
java复制public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
// 执行任务
Thread.sleep(1000);
} catch (InterruptedException e) {
// 恢复中断状态
Thread.currentThread().interrupt();
break;
}
}
}
9.2 不可中断阻塞的处理
对于不响应中断的阻塞操作,需要额外处理:
java复制Future<?> future = executor.submit(task);
try {
future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
future.cancel(true); // 中断任务
}
10. Java内存模型与线程
10.1 happens-before原则
理解这些规则对编写正确并发程序至关重要:
- 程序顺序规则
- 锁规则
- volatile变量规则
- 线程启动规则
- 线程终止规则
- 中断规则
- 终结器规则
- 传递性
10.2 避免内存可见性问题
使用final字段保证安全发布:
java复制class SafePublication {
private final Map<String, String> config;
public SafePublication() {
config = loadConfig(); // 在构造函数中完成初始化
}
}
11. 线程局部变量与性能优化
11.1 ThreadLocal的内存泄漏
正确清理ThreadLocal:
java复制try {
threadLocal.set(value);
// 使用threadLocal
} finally {
threadLocal.remove(); // 必须清理
}
11.2 快速线程局部变量
使用FastThreadLocal(Netty实现)提升性能:
java复制FastThreadLocal<String> fastThreadLocal = new FastThreadLocal<>();
fastThreadLocal.set("value");
String value = fastThreadLocal.get();
12. 并发集合类的选择
12.1 ConcurrentHashMap的使用
java复制ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();
map.compute("key", (k, v) -> v == null ? 1 : v + 1);
12.2 CopyOnWriteArrayList适用场景
适合读多写少的场景:
java复制List<String> list = new CopyOnWriteArrayList<>();
list.add("item"); // 创建新数组副本
String item = list.get(0); // 无需同步
13. 异步编程与CompletableFuture
13.1 链式异步操作
java复制CompletableFuture.supplyAsync(() -> fetchData())
.thenApply(data -> processData(data))
.thenAccept(result -> saveResult(result))
.exceptionally(ex -> {
logger.error("处理失败", ex);
return null;
});
13.2 组合多个Future
java复制CompletableFuture<String> future1 = fetchData1();
CompletableFuture<String> future2 = fetchData2();
CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2);
all.thenRun(() -> {
String result1 = future1.join();
String result2 = future2.join();
// 合并结果
});
14. 线程池的高级配置
14.1 自定义线程池
java复制ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, // 核心线程数
8, // 最大线程数
60, // 空闲时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100), // 工作队列
new ThreadFactory() { // 线程工厂
private final AtomicInteger counter = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "worker-" + counter.getAndIncrement());
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
14.2 选择合适的拒绝策略
- AbortPolicy:默认策略,抛出RejectedExecutionException
- CallerRunsPolicy:由调用线程执行任务
- DiscardPolicy:静默丢弃任务
- DiscardOldestPolicy:丢弃队列中最旧的任务
15. 性能测试与基准比较
15.1 JMH基准测试示例
java复制@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
public class ThreadBenchmark {
private Counter counter = new Counter();
@Benchmark
public void testSynchronized() {
counter.syncIncrement();
}
@Benchmark
public void testAtomic() {
counter.atomicIncrement();
}
static class Counter {
private int syncCount = 0;
private AtomicInteger atomicCount = new AtomicInteger(0);
public synchronized void syncIncrement() {
syncCount++;
}
public void atomicIncrement() {
atomicCount.incrementAndGet();
}
}
}
15.2 不同同步方式的性能对比
根据实际测试结果:
- 无竞争时:volatile ≈ Atomic > synchronized
- 低竞争时:Atomic > synchronized > volatile
- 高竞争时:LongAdder > synchronized ≈ Atomic
16. 实际项目中的线程管理
16.1 全局线程池管理
使用统一工具类管理线程池:
java复制public class ThreadPoolManager {
private static final Map<String, ExecutorService> pools = new ConcurrentHashMap<>();
public static ExecutorService getPool(String name, int size) {
return pools.computeIfAbsent(name,
k -> Executors.newFixedThreadPool(size,
new NamedThreadFactory(k)));
}
public static void shutdownAll() {
pools.values().forEach(pool -> {
pool.shutdown();
try {
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow();
}
} catch (InterruptedException e) {
pool.shutdownNow();
Thread.currentThread().interrupt();
}
});
}
}
16.2 线程泄漏检测
使用弱引用监控线程泄漏:
java复制public class ThreadLeakDetector {
private static final Map<Thread, WeakReference<Thread>> threads =
new ConcurrentHashMap<>();
public static void register(Thread thread) {
threads.put(thread, new WeakReference<>(thread));
}
public static void checkLeaks() {
threads.entrySet().removeIf(entry -> entry.getValue().get() == null);
if (!threads.isEmpty()) {
System.err.println("潜在线程泄漏:");
threads.keySet().forEach(t ->
System.err.println(t.getName() + " - " + t.getState()));
}
}
}
17. 线程与异常处理
17.1 未捕获异常处理
设置全局未捕获异常处理器:
java复制Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
logger.error("线程 " + t.getName() + " 抛出未捕获异常", e);
});
17.2 Future的异常处理
正确处理Future中的异常:
java复制Future<?> future = executor.submit(task);
try {
future.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof BusinessException) {
// 处理业务异常
} else {
// 处理其他异常
}
}
18. 线程上下文与框架集成
18.1 传递线程上下文
在异步任务中传递上下文信息:
java复制public class ContextAwareExecutor implements Executor {
private final Executor delegate;
private final Map<String, Object> context = new HashMap<>();
public ContextAwareExecutor(Executor delegate) {
this.delegate = delegate;
// 捕获当前线程上下文
context.put("user", SecurityContext.getCurrentUser());
// 其他上下文信息...
}
@Override
public void execute(Runnable command) {
Map<String, Object> capturedContext = new HashMap<>(context);
delegate.execute(() -> {
// 恢复上下文
SecurityContext.setCurrentUser((User)capturedContext.get("user"));
try {
command.run();
} finally {
// 清理上下文
SecurityContext.clear();
}
});
}
}
18.2 Spring的@Async集成
配置Spring异步任务执行器:
java复制@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
logger.error("异步方法 " + method.getName() + " 执行失败", ex);
};
}
}
19. 线程与资源清理
19.1 使用try-with-resources
确保线程中使用的资源被正确关闭:
java复制public void processFile(Path file) {
try (InputStream in = Files.newInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
String line;
while ((line = reader.readLine()) != null) {
// 处理每行数据
}
} catch (IOException e) {
Thread.currentThread().interrupt();
throw new UncheckedIOException(e);
}
}
19.2 线程池的资源清理
正确关闭线程池:
java复制executor.shutdown(); // 平缓关闭
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 强制关闭
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("线程池未正常终止");
}
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
20. 线程性能优化技巧
20.1 减少锁竞争
使用锁分解技术:
java复制// 优化前 - 粗粒度锁
class Counter {
private final Object lock = new Object();
private int count1, count2;
public void increment1() {
synchronized(lock) {
count1++;
}
}
public void increment2() {
synchronized(lock) {
count2++;
}
}
}
// 优化后 - 细粒度锁
class OptimizedCounter {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
private int count1, count2;
public void increment1() {
synchronized(lock1) {
count1++;
}
}
public void increment2() {
synchronized(lock2) {
count2++;
}
}
}
20.2 使用无锁数据结构
java复制// 使用ConcurrentLinkedQueue替代同步的LinkedList
Queue<String> queue = new ConcurrentLinkedQueue<>();
// 使用LongAdder替代AtomicLong进行计数
LongAdder adder = new LongAdder();
adder.increment();
long sum = adder.sum();
21. 线程与I/O操作
21.1 异步I/O的最佳实践
使用Java NIO的非阻塞I/O:
java复制AsynchronousFileChannel channel = AsynchronousFileChannel.open(
Paths.get("largefile.bin"), StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
// 处理读取完成的数据
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
// 处理失败情况
}
});
21.2 合理设置I/O密集型任务的线程数
java复制// I/O密集型任务通常需要更多线程
int ioThreads = Runtime.getRuntime().availableProcessors() * 2;
ExecutorService ioExecutor = Executors.newFixedThreadPool(ioThreads);
22. 线程与数据库交互
22.1 连接池配置
合理设置连接池大小:
java复制HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("user");
config.setPassword("pass");
config.setMaximumPoolSize(20); // 通常等于线程池大小
config.setConnectionTimeout(30000);
HikariDataSource dataSource = new HikariDataSource(config);
22.2 事务与线程绑定
确保事务与线程正确关联:
java复制@Transactional
public void processInTransaction() {
// 事务操作
// 注意:不要在事务方法中启动新线程执行数据库操作
}
23. 线程与缓存交互
23.1 缓存并发策略
使用读写锁保护缓存:
java复制class ThreadSafeCache<K, V> {
private final Map<K, V> cache = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public V get(K key) {
lock.readLock().lock();
try {
return cache.get(key);
} finally {
lock.readLock().unlock();
}
}
public void put(K key, V value) {
lock.writeLock().lock();
try {
cache.put(key, value);
} finally {
lock.writeLock().unlock();
}
}
}
23.2 缓存击穿防护
使用双重检查锁定模式:
java复制public V get(K key) {
V value = cache.get(key);
if (value == null) {
synchronized(this) {
value = cache.get(key);
if (value == null) {
value = loadFromDatabase(key);
cache.put(key, value);
}
}
}
return value;
}
24. 线程与分布式系统
24.1 分布式锁实现
基于Redis的分布式锁:
java复制public class RedisDistributedLock {
private final JedisPool jedisPool;
private final String lockKey;
private final String lockValue;
private final int expireTime;
public boolean tryLock(long waitTime, TimeUnit unit) {
long end = System.currentTimeMillis() + unit.toMillis(waitTime);
try (Jedis jedis = jedisPool.getResource()) {
while (System.currentTimeMillis() < end) {
if ("OK".equals(jedis.set(lockKey, lockValue, "NX", "PX", expireTime))) {
return true;
}
Thread.sleep(100);
}
} catch (Exception e) {
Thread.currentThread().interrupt();
}
return false;
}
public void unlock() {
try (Jedis jedis = jedisPool.getResource()) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else return 0 end";
jedis.eval(script, Collections.singletonList(lockKey),
Collections.singletonList(lockValue));
}
}
}
24.2 分布式ID生成
雪花算法实现:
java复制public class SnowflakeIdGenerator {
private final long workerId;
private final long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
throw new IllegalStateException("时钟回拨");
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & 0xFFF;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - 1288834974657L) << 22) |
(datacenterId << 17) |
(workerId << 12) |
sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
}
25. 线程与函数式编程
25.1 并行流的使用
java复制List<String> results = dataList.parallelStream()
.filter(item -> item.startsWith("A"))
.map(String::toUpperCase)
.collect(Collectors.toList());
25.2 CompletableFuture组合
java复制CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> queryService1());
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> queryService2());
CompletableFuture<String> combined = future1.thenCombine(future2, (r1, r2) -> r1 + " " + r2);
26. 线程与测试
26.1 多线程单元测试
使用CountDownLatch同步测试:
java复制@Test
public void testConcurrentAccess() throws InterruptedException {
final int threadCount = 10;
final CountDownLatch startLatch = new CountDownLatch(1);
final CountDownLatch endLatch = new CountDownLatch(threadCount);
final Counter counter = new Counter();
for (int i = 0; i < threadCount; i++) {
new Thread(() -> {
try {
startLatch.await();
counter.increment();
} finally {
endLatch.countDown();
}
}).start();
}
startLatch.countDown();
endLatch.await(10, TimeUnit.SECONDS);
assertEquals(threadCount, counter.getCount());
}
26.2 模拟高并发场景
使用CyclicBarrier模拟并发:
java复制@Test
public void testHighConcurrency() throws Exception {
int threadCount = 50;
CyclicBarrier barrier = new CyclicBarrier(threadCount + 1);
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < threadCount; i++) {
Thread t = new Thread(() -> {
try {
barrier.await(); // 等待所有线程就绪
// 执行测试操作
barrier.await(); // 等待所有线程完成
} catch (Exception e) {
Thread.currentThread().interrupt();
}
});
t.start();
threads.add(t);
}
barrier.await(); // 释放所有线程
barrier.await(); // 等待所有线程完成
// 验证结果
}
27. 线程与JVM调优
27.1 栈大小设置
调整线程栈大小:
bash复制java -Xss256k MyApplication
27.2 线程池与GC调优
监控线程池对GC的影响:
bash复制jstat -gcutil <pid> 1000
28. 线程与网络编程
28.1 非阻塞HTTP客户端
使用异步HTTP客户端:
java复制HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com"))
.build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println)
.exceptionally(e -> {
e.printStackTrace();
return null;
});
28.2 WebSocket多线程处理
java复制WebSocketClient client = new WebSocketClient();
client.addListener(new WebSocketAdapter() {
@Override
public void onTextMessage(WebSocket websocket, String message) {
// 处理消息 - 注意线程安全
}
});
client.connect();
29. 线程与图形界面
29.1 Swing事件分发线程
正确更新UI:
java复制SwingUtilities.invokeLater(() -> {
label.setText("更新后的文本");
});
29.2 JavaFX多线程处理
java复制Platform.runLater(() -> {
label.setText("更新后的文本");
});
30. 线程与文件处理
30.1 多线程文件处理
使用内存映射文件提高性能:
java复制try (RandomAccessFile file = new RandomAccessFile("large.dat", "rw");
FileChannel channel = file.getChannel()) {
MappedByteBuffer buffer = channel.map(
FileChannel.MapMode.READ_WRITE, 0, channel.size());
// 多线程处理buffer
}
30.2 目录遍历并行化
java复制Files.walk(Paths.get("/path/to/dir"))
.parallel()
.filter(Files::isRegularFile)
.forEach(this::processFile);
31. 线程与序列化
31.1 线程安全的序列化
java复制public class ThreadSafeSerialization {
private final Object writeLock = new Object();
private final Object readLock = new Object();
public byte[] serialize(Object obj) throws IOException {
synchronized(writeLock) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(obj);
return bos.toByteArray();
}
}
}
public Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
synchronized(readLock) {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
try (ObjectInputStream ois = new ObjectInputStream(bis)) {
return ois.readObject();
}
}
}
}
31.2 高性能序列化替代方案
考虑使用Kryo或Protobuf:
java复制Kryo kryo = new Kryo();
kryo.register(MyClass.class);
Output output = new Output(new FileOutputStream("file.bin"));
kryo.writeObject(output, myObject);
output.close();
32. 线程与反射
32.1 反射调用的线程安全
缓存Method对象:
java复制class MethodCache {
private static final ConcurrentMap<String, Method> cache = new ConcurrentHashMap<>();
public static Method getMethod(Class<?> clazz, String name, Class<?>... paramTypes)
throws NoSuchMethodException {
String key = clazz.getName() + "#" + name +
Arrays.stream(paramTypes).map(Class::getName).collect(Collectors.joining(","));
return cache.computeIfAbsent(key, k -> {
try {
return clazz.getMethod(name, paramTypes);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
});
}
}
32.2 反射的性能优化
java复制// 设置方法为可访问只需一次
method.setAccessible(true);
// 使用MethodHandle提升性能
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(MyClass.class, "methodName",
MethodType.methodType(void.class));
mh.invokeExact(instance);
33. 线程与本地方法
33.1 JNI调用的线程注意事项
确保本地方法是线程安全的:
java复制public class NativeMethods {
// 声明为同步方法
public synchronized native void threadSafeNativeMethod();
// 或者使用对象锁
private final Object lock = new Object();
public void callNativeMethod() {
synchronized(lock) {
unsafeNativeMethod();
}
}
private native void unsafeNativeMethod();
}
33.2 线程局部存储(TLS)
在本地代码中使用线程局部存储:
c复制#include <pthread.h>
static pthread_key_t key;
void JNI_OnLoad(JavaVM* vm, void* reserved) {
pthread_key_create(&key, NULL);
}
JNIEXPORT void JNICALL Java_com_example_NativeClass_setTls(JNIEnv* env, jobject obj, jlong value) {
pthread_setspecific(key, (void*)value);
}
JNIEXPORT jlong JNICALL Java_com_example_NativeClass_getTls(JNIEnv* env, jobject obj) {
return (jlong)pthread_getspecific(key);
}
34. 线程与安全编程
34.1 安全随机数生成
使用SecureRandom的正确方式:
java复制private static final ThreadLocal<SecureRandom> secureRandom =
ThreadLocal.withInitial(() -> {
try {
return SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e) {
return new SecureRandom();
}
});
public static int generateSecureInt() {
return secureRandom.get().nextInt();
}
34.2 敏感数据清理
及时清理内存中的敏感数据:
java复制public class SecureDataHolder {
private final char[] sensitiveData;
public SecureDataHolder(String data) {
this.sensitiveData = data.toCharArray();
}
public void clear() {
Arrays.fill(sensitiveData, '\0');
}
@Override
protected void finalize() throws Throwable {
try {
clear();
} finally {
super.finalize();
}
}
}
35. 线程与性能分析
35.1 使用JFR监控线程
启用Java Flight Recorder:
bash复制java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder MyApp
35.2 线程争用分析
使用JMC识别热点锁:
bash复制jcmd <pid> JFR.start duration=60s filename=recording.jfr
36. 线程与设计模式
36.1 线程安全的单例模式
双重检查锁定模式:
java复制public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
36.2 生产者-消费者模式
使用BlockingQueue实现:
java复制BlockingQueue<Item> queue = new LinkedBlockingQueue<>(100);
// 生产者
new Thread(() -> {
while (true) {
Item item = produceItem();
queue.put(item);
}
}).start();
// 消费者
new Thread(() -> {
while (true) {
Item item = queue.take();
consumeItem(item);
}
}).start();
37. 线程与注解处理
37.1 自定义线程安全注解
java复制@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ThreadSafe {
String value() default "";
}
@ThreadSafe("使用CAS操作保证线程安全")
public class AtomicCounter {
private final AtomicLong count =
