摘要:线程:Java 中最小的执行单元, THREAD 类和 Runnable 接口是实现线程的基础。同步:多个线程访问共享资源时,确保数据一致性和线程安全。锁:用来控制线程对共享资源的访问,防止数据竞争(Data Race)。线程池:复用线程资源,提高并发性能。无
并发 是指多个任务在同一时间段内执行,而 并行 则是指多个任务在同一时刻同时执行。在多核 CPU 环境下,并行是并发的一种特殊情况。
在 Java 中,并发编程通常涉及到以下几个核心概念:
线程 :Java 中最小的执行单元, THREAD 类和 Runnable 接口是实现线程的基础。同步 :多个线程访问共享资源时,确保数据一致性和线程安全。锁 :用来控制线程对共享资源的访问,防止数据竞争(Data Race)。线程池 :复用线程资源,提高并发性能。无锁编程 :通过原子操作(Atomic)和不可变对象实现高效的并发。多个线程同时访问共享资源时,可能导致数据不一致或逻辑错误。例如在银行转账场景中,若两个线程同时对同一账户进行扣款和入账操作,且未进行同步处理,就可能出现账户金额异常的情况。这是因为线程在读取和修改数据时,可能会受到其他线程的干扰。
高并发环境下,过多的线程竞争有限的资源,如 CPU、内存、数据库连接等,会导致上下文切换频繁,降低系统整体性能。此外,I/O 操作(如网络请求、磁盘读写)的等待时间也会成为性能瓶颈,大量线程在等待 I/O 完成时处于阻塞状态,无法充分利用 CPU 资源。
当多个线程相互持有对方所需的资源,且都不释放自己已持有的资源时,就会形成死锁。例如,线程 A 持有资源 X 并等待资源 Y,线程 B 持有资源 Y 并等待资源 X,此时两个线程都无法继续执行,导致系统部分功能无法正常运行。
实际场景 :在一个电商库存管理系统中,多个订单处理线程可能同时对商品库存进行减扣操作,如果不进行同步控制,可能会出现超卖现象。
解决方案 :
使用 synchronized 关键字public class Inventory { private int stock; public Inventory(int stock) { this.stock = stock; } public synchronized boolean deduct(int quantity) { if (stock >= quantity) { stock -= quantity; return true; } return false; }}使用 Lock 接口import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class InventoryWithLock { private int stock; private Lock lock = new ReentrantLock; public InventoryWithLock(int stock) { this.stock = stock; } public boolean deduct(int quantity) { lock.lock; try { if (stock >= quantity) { stock -= quantity; return true; } return false; } finally { lock.unlock; } }}使用原子类import java.util.concurrent.atomic.AtomicInteger;public class InventoryWithAtomic { private AtomicInteger stock; public InventoryWithAtomic(int stock) { this.stock = new AtomicInteger(stock); } public boolean deduct(int quantity) { int oldValue; do { oldValue = stock.get; if (oldValue实际场景 :一个在线教育平台的直播系统,在上课高峰期会有大量用户同时进入直播间,系统需要快速处理用户请求并保证视频流的稳定传输。
优化策略 :
合理使用线程池import java.util.concurrent.*;public class LiveRoomThreadPool { private static final int CORE_POOL_SIZE = 4 + 1; private static final int MAXIMUM_POOL_SIZE = 4 * 2 + 1; private static final long KEEP_ALIVE_TIME = 10L; private static final TimeUnit UNIT = TimeUnit.SECONDS; private static final BlockingQueue WORK_QUEUE = new ArrayBlockingQueue(1000); private static final ThreadFactory THREAD_FACTORY = new ThreadFactorybuilder .setNameFormat("live-room-thread-pool-%d") .build; private static final RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.CallerRunsPolicy; public static ThreadPoolExecutor getThreadPool { return new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, UNIT, WORK_QUEUE, THREAD_FACTORY, HANDLER ); }}异步处理任务 :对于一些非实时性的任务,如用户观看直播后的学习记录保存、课后作业提交等,可以使用CompletableFuture进行异步处理,避免阻塞主线程。import java.util.concurrent.CompletableFuture;public class AsyncTask { public static void saveStudyRecord(String userId) { CompletableFuture.runAsync( -> { try { Thread.sleep(1000); System.out.println("学习记录已保存,用户ID:" + userId); } catch (InterruptedException e) { e.printStackTrace; } }); }}缓存技术 :使用缓存(如 Redis)存储热点数据,如直播间的课程介绍、讲师信息等,减少对数据库的频繁访问,提高响应速度。实际场景 :在一个任务调度系统中,多个任务可能需要获取多个资源才能执行,若资源分配不当,可能会引发死锁。
检测与避免方法 :
死锁检测 :可以通过 JDK 自带的jconsole或jvisualvm工具来检测死锁。这些工具能够监控线程状态,当检测到死锁时,会给出相关提示。避免死锁 :资源有序分配 :对资源进行编号,线程按照固定的顺序获取资源。例如,线程 A 和线程 B 都需要资源 X 和资源 Y,规定先获取资源 X 再获取资源 Y,这样就不会出现相互等待的情况。 设置超时时间 :在使用Lock接口获取锁时,设置超时时间,如果在规定时间内未获取到锁,则放弃本次尝试,避免无限等待。 import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class DeadlockAvoidance { private Lock lock1 = new ReentrantLock; private Lock lock2 = new ReentrantLock; public void method1 { boolean gotLock1 = false; boolean gotLock2 = false; try { gotLock1 = lock1.tryLock(1, java.util.concurrent.TimeUnit.SECONDS); if (gotLock1) { try { gotLock2 = lock2.tryLock(1, java.util.concurrent.TimeUnit.SECONDS); if (gotLock2) { System.out.println("成功获取锁,执行任务"); } } finally { if (gotLock2) { lock2.unlock; } } } } catch (InterruptedException e) { e.printStackTrace; } finally { if (gotLock1) { lock1.unlock; } } }}Java 中的高并发问题复杂多样,需要开发者深入理解并发编程的原理,并结合实际场景灵活运用各种技术和工具。在解决高并发问题时,应从线程安全、性能优化、死锁避免等多个方面综合考虑。同时,多进行代码实践和性能测试,不断积累经验,才能在面对高并发挑战时游刃有余。通过对经典面试题的学习和分析,希望你能更好地掌握高并发编程知识,在实际开发和面试中取得优异表现。
来源:墨码行者