Java线程与并发编程核心原理与实践

1. Java线程基础概念解析

线程作为Java并发编程的核心概念,理解其本质是掌握多线程编程的第一步。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。在Java中,每个线程都对应一个Thread类的实例。

1.1 线程与进程的区别

线程和进程是现代操作系统的两个基本概念,它们的主要区别体现在以下几个方面:

  • 资源分配 :进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
  • 开销差异 :进程拥有独立的代码和数据空间,切换开销大;线程共享进程资源,切换开销小
  • 内存共享 :同一进程的线程共享地址空间和资源,进程间资源相互独立
  • 健壮性 :一个线程崩溃会导致整个进程终止,而进程崩溃不会影响其他进程
// 进程与线程的关系示例
public class ProcessAndThread {
    public static void main(String[] args) {
        // 主线程(进程中的第一个线程)
        System.out.println("Main thread: " + Thread.currentThread().getName());
        
        // 创建新线程
        new Thread(() -> {
            System.out.println("New thread: " + Thread.currentThread().getName());
        }).start();
    }
}

1.2 线程的生命周期

Java线程在其生命周期中会经历多种状态:

  1. 新建(NEW) :线程对象刚被创建,但尚未启动
  2. 就绪(RUNNABLE) :调用start()后,线程等待CPU时间片
  3. 运行(RUNNING) :线程获得CPU时间片,执行run()方法
  4. 阻塞(BLOCKED) :线程暂时放弃CPU使用权
  5. 终止(TERMINATED) :线程执行完毕或异常退出
// 线程状态观察示例
public class ThreadStateDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        System.out.println("Before start: " + thread.getState()); // NEW
        thread.start();
        System.out.println("After start: " + thread.getState());  // RUNNABLE
        Thread.sleep(500);
        System.out.println("During sleep: " + thread.getState()); // TIMED_WAITING
        thread.join();
        System.out.println("After finish: " + thread.getState()); // TERMINATED
    }
}

2. Java线程创建与管理

2.1 线程创建的三种方式

Java提供了多种创建线程的方式,每种方式都有其适用场景:

  1. 继承Thread类
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread running by extending Thread");
    }
}
// 使用
new MyThread().start();
  1. 实现Runnable接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Thread running by implementing Runnable");
    }
}
// 使用
new Thread(new MyRunnable()).start();
  1. 实现Callable接口(带返回值)
class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "Result from Callable";
    }
}
// 使用
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get()); // 获取返回值
executor.shutdown();

提示:实际开发中推荐使用Runnable或Callable接口方式,因为Java不支持多重继承,使用接口更灵活。

2.2 线程的基本操作

2.2.1 线程启动与中断

正确启动线程应该调用start()方法而非直接调用run()方法。start()会创建新线程执行run()方法,而直接调用run()会在当前线程执行。

// 正确的中断线程方式
public class ThreadInterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Thread is running...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("Thread interrupted during sleep");
                    Thread.currentThread().interrupt(); // 重新设置中断标志
                }
            }
            System.out.println("Thread exiting...");
        });
        
        thread.start();
        Thread.sleep(3000);
        thread.interrupt(); // 中断线程
    }
}
2.2.2 线程等待与通知

wait()/notify()机制是实现线程间通信的基础:

public class WaitNotifyDemo {
    private static final Object lock = new Object();
    private static boolean condition = false;

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (lock) {
                while (!condition) {
                    try {
                        System.out.println("Thread waiting...");
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Thread notified, condition met");
            }
        }).start();

        new Thread(() -> {
            synchronized (lock) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                condition = true;
                lock.notify();
                System.out.println("Notified waiting thread");
            }
        }).start();
    }
}

3. 线程同步与锁机制

3.1 synchronized关键字

synchronized是Java内置的同步机制,可以修饰方法或代码块:

// 同步方法
public synchronized void syncMethod() {
    // 临界区代码
}

// 同步代码块
public void syncBlock() {
    synchronized(this) {
        // 临界区代码
    }
}

synchronized的实现原理:

  • 同步代码块使用monitorenter和monitorexit指令
  • 同步方法使用ACC_SYNCHRONIZED标志
  • 依赖于对象头中的Mark Word实现锁状态记录

3.2 ReentrantLock

ReentrantLock是JDK提供的更灵活的锁实现:

public class ReentrantLockDemo {
    private final ReentrantLock lock = new ReentrantLock();
    
    public void performAction() {
        lock.lock();  // 获取锁
        try {
            // 临界区代码
        } finally {
            lock.unlock();  // 确保锁释放
        }
    }
}

ReentrantLock相比synchronized的优势:

  1. 可中断的锁获取
  2. 公平锁与非公平锁选择
  3. 多个条件变量支持
  4. 尝试获取锁(tryLock)

3.3 volatile关键字

volatile保证变量的可见性和有序性:

public class VolatileDemo {
    private volatile boolean flag = false;
    
    public void writer() {
        flag = true;  // 写操作
    }
    
    public void reader() {
        if (flag) {   // 读操作
            // 基于flag的操作
        }
    }
}

volatile适用场景:

  • 状态标志位
  • 单例模式的双重检查锁定
  • 独立观察(独立于程序状态的状态标志)

4. 线程池原理与实践

4.1 线程池核心参数

ThreadPoolExecutor的构造参数:

public ThreadPoolExecutor(
    int corePoolSize,      // 核心线程数
    int maximumPoolSize,   // 最大线程数
    long keepAliveTime,    // 空闲线程存活时间
    TimeUnit unit,         // 时间单位
    BlockingQueue<Runnable> workQueue, // 工作队列
    ThreadFactory threadFactory,       // 线程工厂
    RejectedExecutionHandler handler   // 拒绝策略
)

4.2 线程池工作流程

  1. 提交任务后,如果当前线程数 < corePoolSize,创建新线程执行任务
  2. 如果线程数 ≥ corePoolSize,将任务放入工作队列
  3. 如果队列已满且线程数 < maximumPoolSize,创建新线程执行任务
  4. 如果队列已满且线程数 ≥ maximumPoolSize,执行拒绝策略

4.3 常见线程池类型

  1. FixedThreadPool :固定大小线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(5);
  1. CachedThreadPool :可缓存线程池
ExecutorService cachedPool = Executors.newCachedThreadPool();
  1. ScheduledThreadPool :定时任务线程池
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3);
  1. SingleThreadExecutor :单线程池
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();

注意:阿里巴巴Java开发手册建议手动创建ThreadPoolExecutor,避免使用Executors工厂方法,因为后者可能创建无界队列导致OOM。

4.4 线程池最佳实践

// 自定义线程池示例
public class CustomThreadPool {
    private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors();
    private static final int MAX_POOL_SIZE = CORE_POOL_SIZE * 2;
    private static final long KEEP_ALIVE_TIME = 1L;
    private static final int QUEUE_CAPACITY = 100;
    
    public static ExecutorService createCustomThreadPool() {
        return new ThreadPoolExecutor(
            CORE_POOL_SIZE,
            MAX_POOL_SIZE,
            KEEP_ALIVE_TIME,
            TimeUnit.MINUTES,
            new LinkedBlockingQueue<>(QUEUE_CAPACITY),
            new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }
}

5. 高级并发工具类

5.1 CountDownLatch

允许一个或多个线程等待其他线程完成操作:

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        int threadCount = 5;
        CountDownLatch latch = new CountDownLatch(threadCount);
        
        for (int i = 0; i < threadCount; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " working");
                latch.countDown();
            }).start();
        }
        
        latch.await();
        System.out.println("All threads completed");
    }
}

5.2 CyclicBarrier

让一组线程到达屏障时被阻塞,直到最后一个线程到达:

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        int threadCount = 3;
        CyclicBarrier barrier = new CyclicBarrier(threadCount, 
            () -> System.out.println("All threads reached barrier"));
        
        for (int i = 0; i < threadCount; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + " waiting");
                    barrier.await();
                    System.out.println(Thread.currentThread().getName() + " continued");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

5.3 Semaphore

控制同时访问特定资源的线程数量:

public class SemaphoreDemo {
    public static void main(String[] args) {
        int permits = 3;
        Semaphore semaphore = new Semaphore(permits);
        
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + " acquired permit");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                    System.out.println(Thread.currentThread().getName() + " released permit");
                }
            }).start();
        }
    }
}

6. 线程安全与性能优化

6.1 线程安全集合

Java并发包提供了多种线程安全集合:

  1. ConcurrentHashMap :分段锁实现的线程安全HashMap
  2. CopyOnWriteArrayList :写时复制的线程安全List
  3. ConcurrentLinkedQueue :无锁实现的线程安全队列
  4. BlockingQueue 接口实现类:ArrayBlockingQueue、LinkedBlockingQueue等
// ConcurrentHashMap使用示例
public class ConcurrentHashMapDemo {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        
        // 线程安全的putIfAbsent
        map.putIfAbsent("key", 1);
        
        // 原子更新
        map.compute("key", (k, v) -> v == null ? 1 : v + 1);
    }
}

6.2 ThreadLocal原理与应用

ThreadLocal为每个线程提供独立的变量副本:

public class ThreadLocalDemo {
    private static final ThreadLocal<SimpleDateFormat> dateFormatHolder =
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
    
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            executor.execute(() -> {
                SimpleDateFormat sdf = dateFormatHolder.get();
                System.out.println(Thread.currentThread().getName() + 
                    " using: " + sdf.format(new Date()));
            });
        }
        executor.shutdown();
    }
}

注意:使用ThreadLocal后必须调用remove()方法清理,避免内存泄漏,特别是在线程池环境中。

6.3 避免死锁的策略

  1. 锁顺序 :所有线程以相同顺序获取锁
  2. 锁超时 :尝试获取锁时设置超时时间
  3. 死锁检测 :定期检查死锁并恢复
  4. 避免嵌套锁 :尽量减少锁的嵌套使用
// 锁顺序示例
public class LockOrderingDemo {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    
    public void method1() {
        synchronized(lock1) {
            synchronized(lock2) {
                // 临界区
            }
        }
    }
    
    public void method2() {
        synchronized(lock1) {  // 与method1相同的锁顺序
            synchronized(lock2) {
                // 临界区
            }
        }
    }
}

7. Java内存模型与happens-before

7.1 Java内存模型(JMM)

JMM定义了线程如何与内存交互,主要关注:

  • 原子性:基本类型读写是原子的(long/double除外)
  • 可见性:一个线程的修改对其他线程可见
  • 有序性:指令重排序的限制

7.2 happens-before原则

  1. 程序顺序规则 :同一线程中的操作按程序顺序执行
  2. 锁规则 :解锁操作先于后续的加锁操作
  3. volatile规则 :volatile写操作先于后续的读操作
  4. 线程启动规则 :Thread.start()先于线程中的任何操作
  5. 线程终止规则 :线程中的所有操作先于线程终止检测
  6. 中断规则 :interrupt()调用先于检测到中断
  7. 终结器规则 :对象构造先于finalize()方法
  8. 传递性 :A happens-before B,B happens-before C,则A happens-before C
// happens-before示例
public class HappensBeforeDemo {
    private int x = 0;
    private volatile boolean v = false;
    
    public void writer() {
        x = 42;    // 1
        v = true;   // 2
    }
    
    public void reader() {
        if (v) {    // 3
            System.out.println(x); // 保证看到42
        }
    }
}

8. 并发编程实践与性能调优

8.1 并发设计模式

  1. 生产者-消费者模式
public class ProducerConsumer {
    private final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
    
    class Producer implements Runnable {
        public void run() {
            try {
                while (true) {
                    queue.put(1);
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Consumer implements Runnable {
        public void run() {
            try {
                while (true) {
                    Integer item = queue.take();
                    System.out.println("Consumed: " + item);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 读写锁模式
public class ReadWriteLockDemo {
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Lock readLock = rwLock.readLock();
    private final Lock writeLock = rwLock.writeLock();
    private Map<String, String> data = new HashMap<>();
    
    public String get(String key) {
        readLock.lock();
        try {
            return data.get(key);
        } finally {
            readLock.unlock();
        }
    }
    
    public void put(String key, String value) {
        writeLock.lock();
        try {
            data.put(key, value);
        } finally {
            writeLock.unlock();
        }
    }
}

8.2 性能优化建议

  1. 减少锁粒度 :缩小同步代码块范围
  2. 减少锁持有时间 :尽快释放锁
  3. 锁分离 :读写锁分离
  4. 无锁编程 :使用CAS操作
  5. 避免热点字段 :如AtomicLong可能成为性能瓶颈
  6. 合理设置线程池参数 :根据任务类型调整
// 锁粒度优化示例
public class LockGranularity {
    private final Map<String, String> map1 = new HashMap<>();
    private final Map<String, String> map2 = new HashMap<>();
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    
    // 细粒度锁
    public void put1(String key, String value) {
        synchronized(lock1) {
            map1.put(key, value);
        }
    }
    
    public void put2(String key, String value) {
        synchronized(lock2) {
            map2.put(key, value);
        }
    }
}

9. Java并发工具进阶

9.1 CompletableFuture

Java 8引入的异步编程工具:

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello";
        }).thenApplyAsync(s -> s + " World")
          .thenApply(String::toUpperCase);
        
        System.out.println(future.get()); // 输出"HELLO WORLD"
    }
}

9.2 Fork/Join框架

适用于分治算法的并行框架:

public class ForkJoinDemo {
    static class FibonacciTask extends RecursiveTask<Long> {
        final long n;
        
        FibonacciTask(long n) { this.n = n; }
        
        protected Long compute() {
            if (n <= 1) return n;
            FibonacciTask f1 = new FibonacciTask(n - 1);
            f1.fork();
            FibonacciTask f2 = new FibonacciTask(n - 2);
            return f2.compute() + f1.join();
        }
    }
    
    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool();
        FibonacciTask task = new FibonacciTask(10);
        System.out.println(pool.invoke(task)); // 输出55
    }
}

10. 常见问题排查与调试

10.1 线程转储分析

获取线程转储的方法:

  1. jstack命令: jstack <pid>
  2. 通过JMX: ThreadMXBean.dumpAllThreads()
  3. 发送信号: kill -3 <pid> (Linux)

分析线程转储关注点:

  • 死锁线程(标记为BLOCKED)
  • 长时间运行的线程
  • 大量等待同一锁的线程
  • 线程状态分布

10.2 常见并发问题

  1. 死锁 :使用jstack检测
  2. 活锁 :线程不断改变状态但无法继续
  3. 饥饿 :低优先级线程长期得不到执行
  4. 竞态条件 :结果依赖于线程执行顺序
  5. 内存一致性错误 :违反happens-before规则

10.3 调试技巧

  1. 使用ThreadLocalRandom :替代Random,减少争用
  2. 避免在锁内调用外部方法 :防止死锁
  3. 使用并发集合 :替代同步包装类
  4. 合理设置线程池大小
    • CPU密集型:CPU核数+1
    • IO密集型:CPU核数*2
// 线程池大小计算示例
public class PoolSizeCalculator {
    public static int getIdealThreadPoolSize() {
        int cores = Runtime.getRuntime().availableProcessors();
        // IO密集型任务
        return (int)(cores / (1 - 0.9)); // 假设阻塞系数为0.9
    }
}

11. Java并发新特性

11.1 Java虚拟线程(Project Loom)

Java 19引入的轻量级线程:

// 虚拟线程使用示例
public class VirtualThreadDemo {
    public static void main(String[] args) throws Exception {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            for (int i = 0; i < 10_000; i++) {
                executor.submit(() -> {
                    Thread.sleep(Duration.ofSeconds(1));
                    return "Done";
                });
            }
        }
    }
}

虚拟线程特点:

  • 由JVM管理,非操作系统线程
  • 创建成本极低,可创建数百万个
  • 阻塞操作不会占用系统线程

11.2 结构化并发(Java 21)

简化多线程编程模型:

// 结构化并发示例
public class StructuredConcurrencyDemo {
    public static void main(String[] args) {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            Future<String> user = scope.fork(() -> findUser());
            Future<Integer> order = scope.fork(() -> fetchOrder());
            
            scope.join();           // 等待所有任务
            scope.throwIfFailed();  // 检查异常
            
            System.out.println("User: " + user.resultNow() + 
                             ", Order: " + order.resultNow());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

12. 并发编程最佳实践

  1. 优先使用高级并发工具 :如并发集合、线程池
  2. 避免过早优化 :先保证正确性,再考虑性能
  3. 编写无状态对象 :减少同步需求
  4. 使用不可变对象 :简化线程安全设计
  5. 文档化线程安全策略 :明确类的线程安全级别
  6. 避免过度同步 :缩小同步范围
  7. 考虑替代方案 :如消息传递、Actor模型
  8. 全面测试并发代码 :包括压力测试和边界测试
// 不可变对象示例
public final class ImmutablePoint {
    private final int x;
    private final int y;
    
    public ImmutablePoint(int x, int y) {
        this.x = x;
        this.y = y;
    }
    
    public int getX() { return x; }
    public int getY() { return y; }
    
    public ImmutablePoint move(int dx, int dy) {
        return new ImmutablePoint(x + dx, y + dy);
    }
}

13. 常见面试问题解析

13.1 synchronized与ReentrantLock区别

特性 synchronized ReentrantLock
实现机制 JVM内置实现 JDK代码实现
锁获取方式 自动获取释放 需要手动lock/unlock
可中断性 不支持 支持lockInterruptibly()
公平锁 非公平 可选择公平/非公平
条件变量 单个等待队列 支持多个Condition
性能 JDK6后优化,性能接近 提供更丰富的功能

13.2 volatile与synchronized区别

特性 volatile synchronized
作用范围 变量级别 变量、方法、代码块级别
原子性 不保证复合操作原子性 保证操作的原子性
可见性 保证可见性 保证可见性
有序性 禁止指令重排序 保证有序性
线程阻塞 不会导致线程阻塞 可能导致线程阻塞
适用场景 状态标志、双重检查锁定 需要原子性操作的场景

13.3 线程池参数配置建议

  1. CPU密集型任务

    • corePoolSize = CPU核数 + 1
    • maximumPoolSize = corePoolSize
    • 使用有界队列防止资源耗尽
  2. IO密集型任务

    • corePoolSize = CPU核数 × 2
    • maximumPoolSize = corePoolSize × 2
    • 使用较大的队列缓冲
  3. 混合型任务

    • 将任务分类,使用不同的线程池处理
    • 监控调整参数达到最佳性能
// 动态调整线程池参数示例
public class DynamicThreadPool extends ThreadPoolExecutor {
    public DynamicThreadPool(int corePoolSize, int maximumPoolSize,
                           long keepAliveTime, TimeUnit unit,
                           BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }
    
    // 动态调整核心线程数
    public void setCorePoolSize(int corePoolSize) {
        super.setCorePoolSize(corePoolSize);
    }
    
    // 动态调整最大线程数
    public void setMaximumPoolSize(int maximumPoolSize) {
        super.setMaximumPoolSize(maximumPoolSize);
    }
}

14. 并发编程的未来趋势

  1. 响应式编程 :如Reactor、RxJava
  2. 协程/虚拟线程 :轻量级并发模型
  3. 无锁数据结构 :提高并发性能
  4. 函数式并发 :不可变数据+纯函数
  5. 分布式并发 :跨JVM的协调机制
  6. 硬件感知并发 :利用NUMA架构特性
// 响应式编程示例
public class ReactiveExample {
    public static void main(String[] args) {
        Flux.range(1, 10)
            .parallel()
            .runOn(Schedulers.parallel())
            .map(i -> i * 2)
            .subscribe(System.out::println);
    }
}

15. 实战经验分享

在实际项目中应用多线程时,我总结了以下几点经验:

  1. 明确并发需求 :不是所有场景都需要并发,评估真正需要并发的部分
  2. 优先使用现有工具 :如并发集合、线程池,避免重复造轮子
  3. 保持简单 :复杂的并发设计难以维护和调试
  4. 全面测试 :包括功能测试、性能测试和压力测试
  5. 监控与调优 :使用JMX、Profiler等工具持续监控
  6. 渐进式优化 :先保证正确性,再逐步优化性能
  7. 文档与注释 :详细记录线程安全策略和并发设计
// 实际项目中的线程安全计数器
public class SafeCounter {
    private final AtomicLong counter = new AtomicLong();
    private final LongAdder fastCounter = new LongAdder();
    
    // 精确计数
    public long incrementAndGet() {
        return counter.incrementAndGet();
    }
    
    // 高性能计数
    public void fastIncrement() {
        fastCounter.increment();
    }
    
    public long fastSum() {
        return fastCounter.sum();
    }
}

16. 性能对比与基准测试

不同并发工具的性能差异:

场景 实现方式 吞吐量(ops/ms) 备注
计数器 synchronized 1,200 高争用时性能下降
计数器 AtomicLong 5,800 CAS实现
计数器 LongAdder 12,400 低争用下最优
Map操作 Hashtable 850 全表锁
Map操作 Collections.synchronizedMap 920 包装器模式
Map操作 ConcurrentHashMap 7,300 分段锁

基准测试建议:使用JMH(Java Microbenchmark Harness)进行可靠的微基准测试,避免JVM优化带来的误差。

// JMH基准测试示例
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class CounterBenchmark {
    @State(Scope.Thread)
    public static class MyState {
        public final AtomicLong atomicCounter = new AtomicLong();
        public final LongAdder adderCounter = new LongAdder();
    }
    
    @Benchmark
    public long testAtomicIncrement(MyState state) {
        return state.atomicCounter.incrementAndGet();
    }
    
    @Benchmark
    public void testAdderIncrement(MyState state) {
        state.adderCounter.increment();
    }
}

17. 并发设计模式进阶

17.1 Thread-Per-Message模式

为每个请求创建独立线程处理:

public class ThreadPerMessageDemo {
    public static void main(String[] args) {
        Host host = new Host();
        host.request(10, 'A');
        host.request(20, 'B');
    }
    
    static class Host {
        private final ExecutorService executor = 
            Executors.newCachedThreadPool();
            
        public void request(int count, char c) {
            executor.execute(() -> {
                for (int i = 0; i < count; i++) {
                    System.out.print(c);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

17.2 Worker Thread模式

使用工作线程池处理任务:

public class WorkerThreadDemo {
    public static void main(String[] args) {
        Channel channel = new Channel(5);
        channel.startWorkers();
        
        new ClientThread("Alice", channel).start();
        new ClientThread("Bobby", channel).start();
    }
    
    static class Channel {
        private final BlockingQueue<Request> queue;
        private final Thread[] threads;
        
        public Channel(int threads) {
            this.queue = new LinkedBlockingQueue<>();
            this.threads = new Thread[threads];
        }
        
        public void startWorkers() {
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new WorkerThread("Worker-" + i, this);
                threads[i].start();
            }
        }
        
        public void putRequest(Request request) {
            try {
                queue.put(request);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        public Request takeRequest() {
            try {
                return queue.take();
            } catch (InterruptedException e) {
                return null;
            }
        }
    }
}

18. 并发调试工具推荐

  1. VisualVM :监控线程状态、内存使用
  2. JConsole :JMX监控工具
  3. JProfiler :商业性能分析工具
  4. YourKit :商业Java Profiler
  5. Arthas :阿里开源的Java诊断工具
  6. jstack :生成线程转储
  7. jcmd :多功能命令行工具

使用jstack分析死锁示例:

# 查找Java进程ID
jps

# 生成线程转储
jstack <pid> > thread_dump.txt

# 分析死锁
grep -A 10 "deadlock" thread_dump.txt

19. 跨语言并发模型比较

语言 主要并发模型 特点
Java 线程+锁 成熟、复杂、JVM优化
Go Goroutine+CSP 轻量级、内置调度器
Erlang Actor模型 容错性强、热代码升级
Rust 所有权+无数据竞争 编译时保证线程安全
C++ 线程+原子操作+各种库 灵活、性能高、复杂度高
JavaScript 事件循环+Promise/async-await 单线程异步、WebWorker多线程

20. 持续学习资源推荐

  1. 书籍

    • 《Java并发编程实战》
    • 《并发编程的艺术》
    • 《Java并发编程之美》
  2. 在线课程

    • Coursera: Parallel Programming in Java
    • Udemy: Java Multithreading, Concurrency & Performance Optimization
  3. 开源项目

    • Netty
    • RxJava
    • Akka
  4. 博客与社区

    • InfoQ并发专栏
    • 美团技术团队博客
    • Stack Overflow并发标签
  5. 实践平台

    • LeetCode多线程题目
    • Codewars并发kata
    • 自己实现小型并发框架
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值