Java并发编程:深入浅出掌握多线程艺术

一、并发编程的定义与重要性

什么是并发编程?

        当我们在单核CPU上边听音乐边写文档时,操作系统通过快速切换任务营造"同时执行"的假象,这就是并发。Java并发编程允许我们创建多个执行线程,充分利用多核CPU的计算能力。

重要性

  • 提升系统吞吐量(如Web服务器同时处理多个请求)

  • 改善用户体验(如后台下载不影响界面响应)

  • 提高资源利用率(如数据库连接池复用)

// 基础线程示例
public class BasicThread {
    public static void main(String[] args) {
        Thread downloadThread = new Thread(() -> {
            System.out.println("开始下载文件...");
            // 模拟耗时操作
            try { Thread.sleep(3000); } catch (InterruptedException e) {}
            System.out.println("文件下载完成");
        });
        
        downloadThread.start();
        System.out.println("主线程继续运行");
    }
}

二、线程安全与共享资源

线程安全陷阱

        当多个线程同时修改共享数据时,可能产生不可预知的结果:

class UnsafeCounter {
    private int count = 0;
    
    public void increment() {
        count++; // 非原子操作
    }
    
    public int getCount() { return count; }
}

// 测试代码
public static void main(String[] args) throws InterruptedException {
    UnsafeCounter counter = new UnsafeCounter();
    
    ExecutorService executor = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 1000; i++) {
        executor.execute(counter::increment);
    }
    
    executor.shutdown();
    executor.awaitTermination(1, TimeUnit.MINUTES);
    
    System.out.println("Final count: " + counter.getCount()); 
    // 预期1000,实际可能输出978等随机值
}

常见问题类型

  1. 数据竞争:未同步的共享数据访问

  2. 死锁:线程互相持有对方所需资源

  3. 活锁:线程不断重试失败操作

// 经典死锁示例
Object lockA = new Object();
Object lockB = new Object();

new Thread(() -> {
    synchronized (lockA) {
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        synchronized (lockB) {
            System.out.println("Thread1 got both locks");
        }
    }
}).start();

new Thread(() -> {
    synchronized (lockB) {
        synchronized (lockA) {
            System.out.println("Thread2 got both locks");
        }
    }
}).start();

死锁问题全场景解决方案

银行家算法实现(预防死锁)

class BankersAlgorithm {
    private int[] available;
    private int[][] max;
    private int[][] allocation;
    private int[][] need;

    public synchronized boolean requestResources(int processId, int[] request) {
        if (!checkRequestValid(processId, request)) return false;
        
        // 试探性分配
        for (int i = 0; i < request.length; i++) {
            available[i] -= request[i];
            allocation[processId][i] += request[i];
            need[processId][i] -= request[i];
        }
        
        if (isSafeState()) {
            return true;
        } else {
            // 回滚操作
            for (int i = 0; i < request.length; i++) {
                available[i] += request[i];
                allocation[processId][i] -= request[i];
                need[processId][i] += request[i];
            }
            return false;
        }
    }
    
    private boolean isSafeState() { /* 安全性检查算法实现 */ }
}

 锁排序解决方案

class Account {
    private int id;
    private BigDecimal balance;
    
    public void transfer(Account target, BigDecimal amount) {
        Account first = id < target.id ? this : target;
        Account second = id < target.id ? target : this;
        
        synchronized(first) {
            synchronized(second) {
                if (this.balance.compareTo(amount) >= 0) {
                    this.balance = this.balance.subtract(amount);
                    target.balance = target.balance.add(amount);
                }
            }
        }
    }
}

tryLock超时机制

class TimeoutLockExample {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();
    
    public boolean transferWithTimeout(long timeout, TimeUnit unit) 
        throws InterruptedException {
        
        long startTime = System.nanoTime();
        while (true) {
            if (lock1.tryLock()) {
                try {
                    if (lock2.tryLock(timeout, unit)) {
                        try {
                            // 执行业务逻辑
                            return true;
                        } finally {
                            lock2.unlock();
                        }
                    }
                } finally {
                    lock1.unlock();
                }
            }
            if (System.nanoTime() - startTime > unit.toNanos(timeout)) {
                return false;
            }
            Thread.sleep(50); // 避免活锁
        }
    }
}

三、同步机制与锁

synchronized关键字

class SafeCounter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public synchronized int getCount() {
        return count;
    }
}

锁升级优化

  • 无锁 → 偏向锁 → 轻量级锁 → 重量级锁

ReentrantLock的灵活控制

class FairCounter {
    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock(true); // 公平锁
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

读写锁应用场景

class CachedData {
    private Object data;
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    
    public void processCachedData() {
        rwLock.readLock().lock();
        if (!dataValid) {
            rwLock.readLock().unlock();
            rwLock.writeLock().lock();
            try {
                // 更新缓存
            } finally {
                rwLock.readLock().lock();
                rwLock.writeLock().unlock();
            }
        }
        // 使用数据
        rwLock.readLock().unlock();
    }
}

四、并发集合与工具类

ConcurrentHashMap的线程安全实现

// 高性能统计(原子操作方法)
ConcurrentHashMap<String, LongAdder> counterMap = new ConcurrentHashMap<>();

public void count(String key) {
    counterMap.computeIfAbsent(key, k -> new LongAdder()).increment();
}

// 分段统计示例
ConcurrentHashMap<String, AtomicLong> map = new ConcurrentHashMap<>();
map.putIfAbsent("key", new AtomicLong(0));
map.get("key").incrementAndGet();

CopyOnWriteArraySet应用场景 

// 监听器列表管理
class EventManager {
    private final CopyOnWriteArraySet<EventListener> listeners = 
        new CopyOnWriteArraySet<>();
    
    public void addListener(EventListener listener) {
        listeners.add(listener);
    }
    
    public void fireEvent(Event event) {
        for (EventListener listener : listeners) {
            executor.execute(() -> listener.onEvent(event));
        }
    }
}

 Disruptor框架(高性能队列)

// 构建Disruptor环形队列
Disruptor<LogEvent> disruptor = new Disruptor<>(
    LogEvent::new, 
    1024, 
    DaemonThreadFactory.INSTANCE,
    ProducerType.MULTI, 
    new BlockingWaitStrategy()
);

disruptor.handleEventsWith((event, sequence, endOfBatch) -> {
    // 处理日志事件
});

RingBuffer<LogEvent> ringBuffer = disruptor.start();

// 发布事件
long sequence = ringBuffer.next();
try {
    LogEvent event = ringBuffer.get(sequence);
    event.setMessage("Log message");
} finally {
    ringBuffer.publish(sequence);
}

同步工具应用示例

// 使用CountDownLatch实现并行任务等待
CountDownLatch latch = new CountDownLatch(3);

Runnable task = () -> {
    // 执行任务
    latch.countDown();
};

new Thread(task).start();
new Thread(task).start();
new Thread(task).start();

latch.await(); // 等待所有任务完成
System.out.println("All tasks completed!");

五、内存模型与可见性

volatile关键字的作用

class VolatileExample {
    private volatile boolean flag = false;
    
    public void writer() {
        flag = true; // 写操作对其他线程立即可见
    }
    
    public void reader() {
        while (!flag) {
            // 当flag变为true时立即跳出循环
        }
    }
}

六、并发性能调优黄金法则

 线程池参数优化公式

最佳线程数 = CPU核心数 * (1 + 等待时间/计算时间)


ThreadPoolExecutor executor = new ThreadPoolExecutor(
    Runtime.getRuntime().availableProcessors(), // 核心线程数
    Runtime.getRuntime().availableProcessors() * 2, // 最大线程数
    60L, TimeUnit.SECONDS, // 空闲线程存活时间
    new LinkedBlockingQueue<>(1000), // 有界队列
    new ThreadFactoryBuilder().setNameFormat("worker-%d").build(),
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

上下文切换优化技巧



@Suspendable
public void coroutineExample() throws SuspendExecution {
    Fiber<Void> fiber1 = new Fiber<Void>(() -> {
        System.out.println("Fiber 1 start");
        Fiber.park(1000); // 挂起1秒
        System.out.println("Fiber 1 resume");
    }).start();
    
    Fiber<Void> fiber2 = new Fiber<Void>(() -> {
        System.out.println("Fiber 2 start");
        Fiber.park(500); // 挂起0.5秒
        System.out.println("Fiber 2 resume");
    }).start();
}

锁消除与锁粗化

// 锁消除示例(JIT编译器优化)
public String concatString(String s1, String s2, String s3) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1); // 自动消除锁(栈封闭)
    sb.append(s2);
    sb.append(s3);
    return sb.toString();
}

// 锁粗化优化前
public void method() {
    synchronized(lock) { /* 操作1 */ }
    synchronized(lock) { /* 操作2 */ }
    synchronized(lock) { /* 操作3 */ }
}

// 优化后
public void method() {
    synchronized(lock) {
        /* 操作1 */
        /* 操作2 */
        /* 操作3 */
    }
}

七、分布式环境下的并发挑战

分布式锁实现方案对比

方案优点缺点适用场景
Redis SETNX实现简单,性能高时钟漂移问题高并发短事务
ZooKeeper强一致性,可靠性高性能较低金融交易等强一致性场景
Etcd高可用,支持租约需要维护连接容器化环境
数据库行锁无需额外组件性能差,死锁风险高低频长事务

RedLock算法实现

public boolean acquireDistributedLock(JedisPool[] jedisPools, String lockKey, 
    String requestId, int expireTime) {
    
    int successCount = 0;
    long startTime = System.currentTimeMillis();
    
    try {
        for (JedisPool pool : jedisPools) {
            try (Jedis jedis = pool.getResource()) {
                if ("OK".equals(jedis.set(lockKey, requestId, "NX", "PX", expireTime))) {
                    successCount++;
                }
            }
        }
        
        long costTime = System.currentTimeMillis() - startTime;
        // 超过半数且操作时间小于锁过期时间
        return successCount >= jedisPools.length/2 + 1 
            && costTime < expireTime;
    } finally {
        if (!acquired) {
            releaseDistributedLock(jedisPools, lockKey, requestId);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伊人秋采唐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值