2025 年 Java 秋招面试必看 Java 并发编程面试题实操篇

本文涉及的产品
无影云电脑企业版,8核16GB 120小时 1个月
轻量应用服务器 2vCPU 1GiB,适用于搭建电商独立站
轻量应用服务器 2vCPU 4GiB,适用于搭建Web应用/小程序
简介: Java并发编程是Java技术栈中非常重要的一部分,也是面试中的高频考点。本文从基础概念、关键机制、工具类、高级技术等多个方面进行了介绍,并提供了丰富的实操示例。希望通过本文的学习,你能够掌握Java并发编程的核心知识,在面试中取得好成绩。同时,在实际工作中,也能够运用这些知识设计和实现高效、稳定的并发系统。

2025年Java秋招面试必看的 | Java并发编程 面试题(实操篇)

四、JUC包下的并发工具类

4.1 ReentrantLock与Condition

4.1.1 基本使用

ReentrantLock是一个可重入的互斥锁,相比synchronized具有更灵活的锁机制。以下是一个使用ReentrantLock实现的生产者-消费者示例:

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumerExample {
   
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final Queue<Integer> queue = new LinkedList<>();
    private final int capacity = 5;

    public void produce(int item) throws InterruptedException {
   
        lock.lock();
        try {
   
            while (queue.size() == capacity) {
   
                notFull.await(); // 队列满时等待
            }
            queue.offer(item);
            System.out.println(Thread.currentThread().getName() + " 生产: " + item);
            notEmpty.signal(); // 通知消费者队列非空
        } finally {
   
            lock.unlock();
        }
    }

    public int consume() throws InterruptedException {
   
        lock.lock();
        try {
   
            while (queue.isEmpty()) {
   
                notEmpty.await(); // 队列空时等待
            }
            int item = queue.poll();
            System.out.println(Thread.currentThread().getName() + " 消费: " + item);
            notFull.signal(); // 通知生产者队列未满
            return item;
        } finally {
   
            lock.unlock();
        }
    }

    public static void main(String[] args) {
   
        ProducerConsumerExample pc = new ProducerConsumerExample();

        // 生产者线程
        Thread producer = new Thread(() -> {
   
            for (int i = 0; i < 10; i++) {
   
                try {
   
                    pc.produce(i);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            }
        }, "Producer");

        // 消费者线程
        Thread consumer = new Thread(() -> {
   
            for (int i = 0; i < 10; i++) {
   
                try {
   
                    pc.consume();
                    Thread.sleep(200);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            }
        }, "Consumer");

        producer.start();
        consumer.start();
    }
}

4.1.2 公平锁与非公平锁

ReentrantLock可以创建公平锁和非公平锁。公平锁会按照线程请求锁的顺序来获取锁,而非公平锁则允许线程在锁释放时直接竞争锁,不考虑请求顺序。以下是创建公平锁的示例:

ReentrantLock fairLock = new ReentrantLock(true); // 创建公平锁

4.2 原子类(AtomicInteger、AtomicLong等)

4.2.1 原子操作示例

Java的原子类提供了高效的原子操作,避免了使用锁的开销。以下是一个使用AtomicInteger实现计数器的示例:

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicCounter {
   
    private AtomicInteger count = new AtomicInteger(0);

    public void increment() {
   
        count.incrementAndGet();
    }

    public int getCount() {
   
        return count.get();
    }

    public static void main(String[] args) throws InterruptedException {
   
        AtomicCounter counter = new AtomicCounter();
        int threadCount = 10;
        Thread[] threads = new Thread[threadCount];

        // 创建并启动多个线程
        for (int i = 0; i < threadCount; i++) {
   
            threads[i] = new Thread(() -> {
   
                for (int j = 0; j < 1000; j++) {
   
                    counter.increment();
                }
            });
            threads[i].start();
        }

        // 等待所有线程完成
        for (Thread thread : threads) {
   
            thread.join();
        }

        System.out.println("最终计数: " + counter.getCount()); // 输出应为10000
    }
}

4.2.2 CAS操作原理

原子类的底层实现基于CAS(Compare - And - Swap)操作。CAS是一种无锁算法,包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。以下是一个简单的CAS操作示例:

import java.util.concurrent.atomic.AtomicInteger;

public class CASExample {
   
    private AtomicInteger value = new AtomicInteger(10);

    public void compareAndSet(int expected, int newValue) {
   
        boolean success = value.compareAndSet(expected, newValue);
        System.out.println("操作结果: " + success);
    }

    public static void main(String[] args) {
   
        CASExample example = new CASExample();
        example.compareAndSet(10, 20); // 操作成功,值变为20
        example.compareAndSet(10, 30); // 操作失败,值仍为20
    }
}

4.3 并发集合(ConcurrentHashMap、CopyOnWriteArrayList等)

4.3.1 ConcurrentHashMap使用

ConcurrentHashMap是线程安全的哈希表实现,在多线程环境下可以高效地进行读写操作。以下是一个使用ConcurrentHashMap的示例:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
   
    private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

    public void add(String key, int value) {
   
        map.put(key, value);
    }

    public int get(String key) {
   
        return map.getOrDefault(key, 0);
    }

    public void remove(String key) {
   
        map.remove(key);
    }

    public static void main(String[] args) {
   
        ConcurrentHashMapExample example = new ConcurrentHashMapExample();

        // 多个线程并发操作map
        Thread t1 = new Thread(() -> {
   
            for (int i = 0; i < 1000; i++) {
   
                example.add("key" + i, i);
            }
        });

        Thread t2 = new Thread(() -> {
   
            for (int i = 0; i < 1000; i++) {
   
                int value = example.get("key" + i);
                System.out.println("key" + i + ": " + value);
            }
        });

        t1.start();
        t2.start();

        try {
   
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }
    }
}

4.3.2 CopyOnWriteArrayList原理

CopyOnWriteArrayList是一个线程安全的列表实现,它在修改操作时会创建底层数组的一个副本,从而避免了在迭代过程中出现ConcurrentModificationException。以下是一个使用CopyOnWriteArrayList的示例:

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
   
    private CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

    public void add(String element) {
   
        list.add(element);
    }

    public void iterate() {
   
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
   
            System.out.println(iterator.next());
        }
    }

    public static void main(String[] args) {
   
        CopyOnWriteArrayListExample example = new CopyOnWriteArrayListExample();

        // 线程1添加元素
        Thread t1 = new Thread(() -> {
   
            for (int i = 0; i < 10; i++) {
   
                example.add("element" + i);
                try {
   
                    Thread.sleep(100);
                } catch (InterruptedException e) {
   
                    e.printStackTrace();
                }
            }
        });

        // 线程2迭代列表
        Thread t2 = new Thread(() -> {
   
            try {
   
                Thread.sleep(200);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
            example.iterate();
        });

        t1.start();
        t2.start();
    }
}

4.4 线程池(ExecutorService、ScheduledExecutorService等)

4.4.1 线程池的创建与使用

线程池可以有效地管理和复用线程,提高系统性能。以下是一个使用Executors工厂类创建线程池的示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExample {
   
    public static void main(String[] args) {
   
        // 创建一个固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 提交任务到线程池
        for (int i = 0; i < 10; i++) {
   
            final int taskId = i;
            executor.submit(() -> {
   
                System.out.println("任务 " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行");
                try {
   
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
                System.out.println("任务 " + taskId + " 执行完成");
            });
        }

        // 关闭线程池
        executor.shutdown();
        try {
   
            // 等待所有任务完成
            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
   
                // 超时后强制关闭
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
   
            // 再次调用shutdownNow
            executor.shutdownNow();
        }
    }
}

4.4.2 自定义线程池

实际生产环境中,推荐使用ThreadPoolExecutor类来自定义线程池,以满足特定需求。以下是一个自定义线程池的示例:

import java.util.concurrent.*;

public class CustomThreadPoolExample {
   
    public static void main(String[] args) {
   
        // 创建自定义线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                2, // 核心线程数
                5, // 最大线程数
                60, // 线程空闲时间
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10), // 任务队列
                Executors.defaultThreadFactory(), // 线程工厂
                new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );

        // 提交任务
        for (int i = 0; i < 20; i++) {
   
            final int taskId = i;
            executor.submit(() -> {
   
                System.out.println("任务 " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行");
                try {
   
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}

4.5 信号量(Semaphore)

4.5.1 基本使用

Semaphore是一个计数信号量,用于控制同时访问某个资源的线程数量。以下是一个使用Semaphore实现资源池的示例:

import java.util.concurrent.Semaphore;

public class ResourcePool {
   
    private final Semaphore semaphore;
    private final int maxResources;
    private final boolean[] resources;

    public ResourcePool(int maxResources) {
   
        this.maxResources = maxResources;
        this.resources = new boolean[maxResources];
        this.semaphore = new Semaphore(maxResources, true); // 创建公平信号量
    }

    public int acquire() throws InterruptedException {
   
        semaphore.acquire(); // 获取许可
        return getResource();
    }

    public void release(int resourceId) {
   
        markResourceAsFree(resourceId);
        semaphore.release(); // 释放许可
    }

    private synchronized int getResource() {
   
        for (int i = 0; i < maxResources; i++) {
   
            if (!resources[i]) {
   
                resources[i] = true;
                return i;
            }
        }
        return -1; // 不会发生,因为已经获取了许可
    }

    private synchronized void markResourceAsFree(int resourceId) {
   
        resources[resourceId] = false;
    }

    public static void main(String[] args) {
   
        ResourcePool pool = new ResourcePool(3);

        // 创建10个线程竞争资源
        for (int i = 0; i < 10; i++) {
   
            new Thread(() -> {
   
                try {
   
                    int resourceId = pool.acquire();
                    System.out.println(Thread.currentThread().getName() + " 获取资源 " + resourceId);
                    Thread.sleep(1000);
                    pool.release(resourceId);
                    System.out.println(Thread.currentThread().getName() + " 释放资源 " + resourceId);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            }, "Thread-" + i).start();
        }
    }
}

4.6 倒计时门闩(CountDownLatch)

4.6.1 基本使用

CountDownLatch用于让一个或多个线程等待其他线程完成操作。以下是一个使用CountDownLatch的示例:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
   
    public static void main(String[] args) throws InterruptedException {
   
        int workerCount = 5;
        CountDownLatch latch = new CountDownLatch(workerCount);

        // 创建并启动多个工作线程
        for (int i = 0; i < workerCount; i++) {
   
            final int workerId = i;
            new Thread(() -> {
   
                System.out.println("工作线程 " + workerId + " 开始工作");
                try {
   
                    // 模拟工作
                    Thread.sleep((long) (Math.random() * 5000));
                    System.out.println("工作线程 " + workerId + " 完成工作");
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                } finally {
   
                    latch.countDown(); // 计数减1
                }
            }).start();
        }

        // 主线程等待所有工作线程完成
        System.out.println("主线程等待工作线程完成...");
        latch.await();
        System.out.println("所有工作线程已完成,主线程继续执行");
    }
}

4.7 循环屏障(CyclicBarrier)

4.7.1 基本使用

CyclicBarrier用于让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续执行。以下是一个使用CyclicBarrier的示例:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
   
    public static void main(String[] args) {
   
        int threadCount = 3;
        CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> {
   
            System.out.println("所有线程都到达屏障,继续执行");
        });

        // 创建并启动多个线程
        for (int i = 0; i < threadCount; i++) {
   
            final int threadId = i;
            new Thread(() -> {
   
                System.out.println("线程 " + threadId + " 开始执行");
                try {
   
                    // 模拟工作
                    Thread.sleep((long) (Math.random() * 3000));
                    System.out.println("线程 " + threadId + " 到达屏障");
                    barrier.await(); // 等待其他线程到达屏障
                    System.out.println("线程 " + threadId + " 继续执行");
                } catch (InterruptedException | BrokenBarrierException e) {
   
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

4.8 交换器(Exchanger)

4.8.1 基本使用

Exchanger用于两个线程之间交换数据。以下是一个使用Exchanger的示例:

import java.util.concurrent.Exchanger;

public class ExchangerExample {
   
    public static void main(String[] args) {
   
        Exchanger<String> exchanger = new Exchanger<>();

        // 第一个线程
        Thread thread1 = new Thread(() -> {
   
            try {
   
                String data1 = "线程1的数据";
                System.out.println("线程1发送: " + data1);
                String receivedData = exchanger.exchange(data1);
                System.out.println("线程1接收: " + receivedData);
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
        });

        // 第二个线程
        Thread thread2 = new Thread(() -> {
   
            try {
   
                String data2 = "线程2的数据";
                System.out.println("线程2发送: " + data2);
                String receivedData = exchanger.exchange(data2);
                System.out.println("线程2接收: " + receivedData);
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
        });

        thread1.start();
        thread2.start();
    }
}

五、高级并发编程技术

5.1 CompletableFuture

5.1.1 异步任务链

CompletableFuture是Java 8引入的用于处理异步计算的类,它可以方便地构建异步任务链。以下是一个使用CompletableFuture的示例:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class CompletableFutureExample {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        // 创建自定义线程池
        var executor = Executors.newFixedThreadPool(2);

        // 异步任务1:获取用户ID
        CompletableFuture<String> userIdFuture = CompletableFuture.supplyAsync(() -> {
   
            try {
   
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
            System.out.println("获取用户ID");
            return "user123";
        }, executor);

        // 异步任务2:根据用户ID获取订单信息
        CompletableFuture<String> orderFuture = userIdFuture.thenApplyAsync(userId -> {
   
            try {
   
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
            System.out.println("获取用户 " + userId + " 的订单信息");
            return "order456";
        }, executor);

        // 异步任务3:根据订单信息获取物流信息
        CompletableFuture<String> logisticsFuture = orderFuture.thenApplyAsync(orderId -> {
   
            try {
   
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
            System.out.println("获取订单 " + orderId + " 的物流信息");
            return "物流信息:已发货";
        }, executor);

        // 最终结果处理
        logisticsFuture.thenAccept(logisticsInfo -> {
   
            System.out.println("最终结果:" + logisticsInfo);
            executor.shutdown();
        });

        // 主线程不需要等待,可以继续执行其他任务
        System.out.println("主线程继续执行");
    }
}

5.1.2 组合多个CompletableFuture

CompletableFuture提供了多种方法来组合多个异步任务。以下是一个组合多个CompletableFuture的示例:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureCombinationExample {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        // 任务1:计算两个数的和
        CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(() -> 2 + 3);

        // 任务2:计算两个数的乘积
        CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> 4 * 5);

        // 组合两个任务的结果
        CompletableFuture<Integer> combinedFuture = task1.thenCombine(task2, (sum, product) -> sum + product);

        // 获取最终结果
        System.out.println("最终结果: " + combinedFuture.get()); // 输出: 25
    }
}

5.2 响应式编程(Reactor)

5.2.1 基本使用

Reactor是Java生态中主流的响应式编程框架,基于Reactive Streams规范。以下是一个使用Reactor的简单示例:

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.time.Duration;

public class ReactorExample {
   
    public static void main(String[] args) throws InterruptedException {
   
        // 创建一个Flux,发出1到5的整数
        Flux<Integer> numbers = Flux.range(1, 5);

        // 对每个元素进行平方操作,并在另一个线程上执行
        Flux<Integer> squaredNumbers = numbers
                .publishOn(Schedulers.boundedElastic())
                .map(n -> {
   
                    System.out.println("处理元素 " + n + " 在线程 " + Thread.currentThread().getName());
                    return n * n;
                });

        // 订阅并处理结果
        squaredNumbers.subscribe(
                num -> System.out.println("收到元素: " + num),
                error -> System.err.println("错误: " + error),
                () -> System.out.println("处理完成")
        );

        // 创建一个Mono,延迟1秒后发出一个值
        Mono.just("Hello, Reactor!")
                .delayElement(Duration.ofSeconds(1))
                .subscribe(System.out::println);

        // 主线程等待,以便异步操作有时间完成
        Thread.sleep(2000);
    }
}

5.2.2 背压处理

响应式编程中的背压是处理生产者与消费者速度不匹配的机制。以下是一个使用背压的示例:

import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;

import java.time.Duration;

public class BackpressureExample {
   
    public static void main(String[] args) throws InterruptedException {
   
        // 创建一个快速生产者,每秒发出1000个元素
        Flux<Integer> fastProducer = Flux.interval(Duration.ofMillis(1))
                .map(i -> {
   
                    System.out.println("生产者发出: " + i);
                    return i.intValue();
                });

        // 创建一个慢速消费者,每500毫秒处理一个元素
        fastProducer
                .onBackpressureBuffer(100) // 设置缓冲区大小为100
                .publishOn(Schedulers.boundedElastic(), 1) // 每次只请求1个元素
                .subscribe(
                        item -> {
   
                            try {
   
                                Thread.sleep(500);
                                System.out.println("消费者处理: " + item);
                            } catch (InterruptedException e) {
   
                                Thread.currentThread().interrupt();
                            }
                        },
                        error -> System.err.println("错误: " + error.getMessage())
                );

        // 主线程等待
        Thread.sleep(10000);
    }
}

5.3 协程(Project Loom)

5.3.1 基本使用

Project Loom是Java平台上的一个重大改进,引入了轻量级线程(协程)的概念。以下是一个使用协程的示例:

import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class VirtualThreadExample {
   
    public static void main(String[] args) throws InterruptedException {
   
        // 创建一个虚拟线程执行器
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

        // 提交大量任务
        for (int i = 0; i < 10000; i++) {
   
            final int taskId = i;
            executor.submit(() -> {
   
                try {
   
                    // 模拟IO操作
                    Thread.sleep(Duration.ofMillis(100));
                    System.out.println("任务 " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行");
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 关闭执行器
        executor.shutdown();
        executor.awaitTermination(1, java.util.concurrent.TimeUnit.MINUTES);
    }
}

5.3.2 协程与传统线程对比

以下是一个简单的对比示例,展示协程在处理大量并发任务时的优势:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadVsVirtualThreadComparison {
   
    private static final int TASK_COUNT = 100000;

    public static void main(String[] args) throws InterruptedException {
   
        // 测试传统线程
        testTraditionalThreads();

        // 测试虚拟线程
        testVirtualThreads();
    }

    private static void testTraditionalThreads() throws InterruptedException {
   
        long startTime = System.currentTimeMillis();
        ExecutorService executor = Executors.newFixedThreadPool(200);

        for (int i = 0; i < TASK_COUNT; i++) {
   
            final int taskId = i;
            executor.submit(() -> {
   
                try {
   
                    Thread.sleep(100);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            });
        }

        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);

        long endTime = System.currentTimeMillis();
        System.out.println("传统线程耗时: " + (endTime - startTime) + " ms");
    }

    private static void testVirtualThreads() throws InterruptedException {
   
        long startTime = System.currentTimeMillis();
        ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

        for (int i = 0; i < TASK_COUNT; i++) {
   
            final int taskId = i;
            executor.submit(() -> {
   
                try {
   
                    Thread.sleep(100);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            });
        }

        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.MINUTES);

        long endTime = System.currentTimeMillis();
        System.out.println("虚拟线程耗时: " + (endTime - startTime) + " ms");
    }
}

六、并发编程最佳实践

6.1 线程安全的设计原则

  1. 不可变对象:使用不可变对象可以从根本上避免线程安全问题。例如,String类就是不可变的,在多线程环境下可以安全使用。
  2. 线程封闭:将对象限制在单个线程中,避免多个线程访问共享资源。例如,使用ThreadLocal存储线程私有的数据。
  3. 使用线程安全的类:优先使用JDK提供的线程安全类,如ConcurrentHashMap、CopyOnWriteArrayList等。
  4. 同步机制:在必要时使用synchronized关键字或ReentrantLock等同步机制来保护共享资源。

6.2 性能优化策略

  1. 减少锁的粒度:只在必要的代码块上使用锁,避免锁住整个方法或类。
  2. 使用无锁数据结构:如原子类(AtomicInteger、AtomicLong等),利用CAS操作避免锁的使用。
  3. 线程池的合理配置:根据业务场景合理配置线程池的核心线程数、最大线程数和任务队列大小。
  4. 异步编程:使用CompletableFuture、Reactor等框架进行异步编程,提高系统的吞吐量。

6.3 死锁的预防与检测

  1. 死锁预防
    • 按顺序获取锁:确保所有线程按照相同的顺序获取锁。
    • 设置锁超时:使用ReentrantLock的tryLock(long timeout, TimeUnit unit)方法。
    • 避免嵌套锁:尽量避免在持有一个锁的情况下获取另一个锁。
  2. 死锁检测
    • 使用jstack命令:可以查看线程的堆栈信息,找出可能的死锁。
    • 使用工具:如VisualVM、YourKit等工具可以检测死锁。

以下是一个检测死锁的示例代码:

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class DeadlockDetector {
   
    private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

    public static void start() {
   
        Thread detector = new Thread(() -> {
   
            while (true) {
   
                long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
                if (deadlockedThreads != null) {
   
                    ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(deadlockedThreads);
                    System.err.println("发现死锁!");
                    for (ThreadInfo info : threadInfos) {
   
                        System.err.println(info);
                    }
                }
                try {
   
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            }
        });
        detector.setDaemon(true);
        detector.start();
    }

    public static void main(String[] args) {
   
        // 启动死锁检测器
        start();

        // 模拟死锁
        Object lock1 = new Object();
        Object lock2 = new Object();

        Thread t1 = new Thread(() -> {
   
            synchronized (lock1) {
   
                System.out.println("线程1获取了锁1");
                try {
   
                    Thread.sleep(100);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
                synchronized (lock2) {
   
                    System.out.println("线程1获取了锁2");
                }
            }
        });

        Thread t2 = new Thread(() -> {
   
            synchronized (lock2) {
   
                System.out.println("线程2获取了锁2");
                try {
   
                    Thread.sleep(100);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
                synchronized (lock1) {
   
                    System.out.println("线程2获取了锁1");
                }
            }
        });

        t1.start();
        t2.start();
    }
}

七、面试题实战

7.1 高频面试题解答

7.1.1 如何实现一个线程安全的单例模式?

// 双重检查锁定实现线程安全的单例模式
public class Singleton {
   
    private static volatile Singleton instance; // 使用volatile保证可见性和有序性

    private Singleton() {
   }

    public static Singleton getInstance() {
   
        if (instance == null) {
    // 第一次检查
            synchronized (Singleton.class) {
   
                if (instance == null) {
    // 第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

7.1.2 如何实现生产者-消费者模式?

可以使用多种方式实现生产者-消费者模式,以下是使用BlockingQueue的实现:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class ProducerConsumerWithBlockingQueue {
   
    private static final BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);

    public static void main(String[] args) {
   
        // 生产者线程
        Thread producer = new Thread(() -> {
   
            try {
   
                for (int i = 0; i < 10; i++) {
   
                    queue.put(i);
                    System.out.println("生产者生产: " + i);
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
        });

        // 消费者线程
        Thread consumer = new Thread(() -> {
   
            try {
   
                for (int i = 0; i < 10; i++) {
   
                    Integer item = queue.take();
                    System.out.println("消费者消费: " + item);
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
        });

        producer.start();
        consumer.start();
    }
}

7.1.3 如何优化高并发场景下的性能?

优化高并发场景下的性能可以从以下几个方面入手:

  1. 减少锁的使用:使用无锁数据结构,如ConcurrentHashMap、原子类等。
  2. 异步处理:使用CompletableFuture、Reactor等框架处理异步任务,避免阻塞线程。
  3. 缓存:使用本地缓存(如Caffeine)或分布式缓存(如Redis)减少数据库访问。
  4. 限流:使用令牌桶、漏桶等算法进行限流,防止系统过载。
  5. 分库分表:在数据库层面进行分库分表,提高数据库的并发处理能力。

7.1.4 如何处理分布式系统中的并发问题?

处理分布式系统中的并发问题可以采用以下方法:

  1. 分布式锁:使用Redis、ZooKeeper等实现分布式锁,保证同一时刻只有一个线程可以访问共享资源。
  2. 乐观锁:在数据库表中添加版本号字段,通过CAS操作实现乐观锁。
  3. 幂等设计:确保服务的接口具有幂等性,避免重复操作导致的数据不一致。
  4. 最终一致性:采用异步通信和补偿机制,保证系统的最终一致性。

7.2 实战演练

7.2.1 实现一个简单的线程池

import java.util.LinkedList;
import java.util.Queue;

public class SimpleThreadPool {
   
    private final int poolSize;
    private final WorkerThread[] workers;
    private final Queue<Runnable> taskQueue;
    private boolean isShutdown = false;

    public SimpleThreadPool(int poolSize) {
   
        this.poolSize = poolSize;
        this.taskQueue = new LinkedList<>();
        this.workers = new WorkerThread[poolSize];

        // 初始化工作线程
        for (int i = 0; i < poolSize; i++) {
   
            workers[i] = new WorkerThread();
            workers[i].start();
        }
    }

    public synchronized void execute(Runnable task) {
   
        if (isShutdown) {
   
            throw new IllegalStateException("线程池已关闭");
        }
        taskQueue.add(task);
        notify(); // 唤醒等待的工作线程
    }

    public synchronized void shutdown() {
   
        isShutdown = true;
        for (WorkerThread worker : workers) {
   
            worker.interrupt();
        }
    }

    private class WorkerThread extends Thread {
   
        @Override
        public void run() {
   
            while (!isInterrupted()) {
   
                Runnable task;
                synchronized (SimpleThreadPool.this) {
   
                    while (taskQueue.isEmpty() && !isShutdown) {
   
                        try {
   
                            wait(); // 没有任务时等待
                        } catch (InterruptedException e) {
   
                            interrupt();
                        }
                    }
                    if (isShutdown && taskQueue.isEmpty()) {
   
                        break;
                    }
                    task = taskQueue.poll();
                }
                if (task != null) {
   
                    try {
   
                        task.run();
                    } catch (Exception e) {
   
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
   
        SimpleThreadPool threadPool = new SimpleThreadPool(3);

        // 提交任务
        for (int i = 0; i < 10; i++) {
   
            final int taskId = i;
            threadPool.execute(() -> {
   
                System.out.println("任务 " + taskId + " 由线程 " + Thread.currentThread().getName() + " 执行");
                try {
   
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
   
                    Thread.currentThread().interrupt();
                }
            });
        }

        // 关闭线程池
        try {
   
            Thread.sleep(5000);
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }
        threadPool.shutdown();
    }
}

7.2.2 使用CompletableFuture实现异步数据聚合

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AsyncDataAggregation {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // 模拟从不同服务获取数据
        CompletableFuture<String> userInfoFuture = CompletableFuture.supplyAsync(() -> {
   
            try {
   
                Thread.sleep(1000);
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
            return "用户信息:ID=123,姓名=张三";
        }, executor);

        CompletableFuture<String> orderInfoFuture = CompletableFuture.supplyAsync(() -> {
   
            try {
   
                Thread.sleep(1500);
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
            return "订单信息:订单号=456,金额=100.00元";
        }, executor);

        CompletableFuture<String> paymentInfoFuture = CompletableFuture.supplyAsync(() -> {
   
            try {
   
                Thread.sleep(800);
            } catch (InterruptedException e) {
   
                Thread.currentThread().interrupt();
            }
            return "支付信息:支付方式=支付宝,状态=已支付";
        }, executor);

        // 聚合所有数据
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                userInfoFuture, orderInfoFuture, paymentInfoFuture
        );

        // 当所有任务完成后,处理结果
        CompletableFuture<String> combinedFuture = allFutures.thenApply(v -> {
   
            try {
   
                return userInfoFuture.get() + "\n" +
                        orderInfoFuture.get() + "\n" +
                        paymentInfoFuture.get();
            } catch (InterruptedException | ExecutionException e) {
   
                throw new RuntimeException(e);
            }
        });

        // 获取最终结果
        System.out.println("聚合结果:\n" + combinedFuture.get());

        // 关闭线程池
        executor.shutdown();
    }
}

八、总结

Java并发编程是Java技术栈中非常重要的一部分,也是面试中的高频考点。本文从基础概念、关键机制、工具类、高级技术等多个方面进行了介绍,并提供了丰富的实操示例。希望通过本文的学习,你能够掌握Java并发编程的核心知识,在面试中取得好成绩。同时,在实际工作中,也能够运用这些知识设计和实现高效、稳定的并发系统。

---2025 年 Java 秋招,Java 秋招面



代码获取方式
https://pan.quark.cn/s/14fcf913bae6


相关文章
|
16天前
|
自然语言处理 前端开发 Java
JBoltAI 框架完整实操案例 在 Java 生态中快速构建大模型应用全流程实战指南
本案例基于JBoltAI框架,展示如何快速构建Java生态中的大模型应用——智能客服系统。系统面向电商平台,具备自动回答常见问题、意图识别、多轮对话理解及复杂问题转接人工等功能。采用Spring Boot+JBoltAI架构,集成向量数据库与大模型(如文心一言或通义千问)。内容涵盖需求分析、环境搭建、代码实现(知识库管理、核心服务、REST API)、前端界面开发及部署测试全流程,助你高效掌握大模型应用开发。
103 5
|
14天前
|
算法 Java API
2025 版 Java 零基础入门到精通实操指南
这篇文章为零基础学习者提供了Java入门的全面指南。首先介绍了Java的特点和用途,然后详细讲解了环境搭建步骤(JDK安装、环境变量配置和IDE选择),并以&quot;Hello World&quot;程序为例演示了开发流程。文章还系统性地讲解了Java核心语法,包括变量与数据类型、运算符、控制流语句、数组和方法等基础知识,以及面向对象编程和异常处理的概念。通过代码示例帮助读者理解和实践,最后建议掌握基础后可进一步学习Java高级特性和框架。文中还提供了代码获取方式和关注入口,适合Java初学者系统学习。
354 2
|
20天前
|
存储 安全 Java
常见 JAVA 集合面试题整理 自用版持续更新
这是一份详尽的Java集合面试题总结,涵盖ArrayList与LinkedList、HashMap与HashTable、HashSet与TreeSet的区别,以及ConcurrentHashMap的实现原理。内容从底层数据结构、性能特点到应用场景逐一剖析,并提供代码示例便于理解。此外,还介绍了如何遍历HashMap和HashTable。无论是初学者还是进阶开发者,都能从中受益。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
59 3
|
18天前
|
安全 Java API
Java 17 + 特性与现代开发技术实操应用详解
本指南聚焦Java 17+最新技术,涵盖模块化开发、Record类、模式匹配、文本块、Stream API增强、虚拟线程等核心特性,结合Spring Boot 3与Micronaut框架实战。通过实操案例解析现代Java开发技术栈,包括高性能并发编程、GraalVM原生编译及开发工具链配置。同时梳理面试高频考点,助力掌握Java新特性和实际应用,适合学习与项目实践。代码示例丰富,附带完整资源下载链接。
236 0
|
19天前
|
存储 安全 Java
2025 最新史上最全 Java 面试题独家整理带详细答案及解析
本文从Java基础、面向对象、多线程与并发等方面详细解析常见面试题及答案,并结合实际应用帮助理解。内容涵盖基本数据类型、自动装箱拆箱、String类区别,面向对象三大特性(封装、继承、多态),线程创建与安全问题解决方法,以及集合框架如ArrayList与LinkedList的对比和HashMap工作原理。适合准备面试或深入学习Java的开发者参考。附代码获取链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
151 48
|
16天前
|
消息中间件 机器学习/深度学习 Java
java 最新技术驱动的智能教育在线实验室设备管理与实验资源优化实操指南
这是一份基于最新技术的智能教育在线实验室设备管理与实验资源优化的实操指南,涵盖系统搭建、核心功能实现及优化策略。采用Flink实时处理、Kafka消息队列、Elasticsearch搜索分析和Redis缓存等技术栈,结合强化学习动态优化资源调度。指南详细描述了开发环境准备、基础组件部署、数据采集与处理、模型训练、API服务集成及性能调优步骤,支持高并发设备接入与低延迟处理,满足教育机构数字化转型需求。代码已提供下载链接,助力快速构建智能化实验室管理系统。
82 44
|
16天前
|
缓存 监控 NoSQL
Redis 实操要点:Java 最新技术栈的实战解析
本文介绍了基于Spring Boot 3、Redis 7和Lettuce客户端的Redis高级应用实践。内容包括:1)现代Java项目集成Redis的配置方法;2)使用Redisson实现分布式可重入锁与公平锁;3)缓存模式解决方案,包括布隆过滤器防穿透和随机过期时间防雪崩;4)Redis数据结构的高级应用,如HyperLogLog统计UV和GeoHash处理地理位置。文章提供了详细的代码示例,涵盖Redis在分布式系统中的核心应用场景,特别适合需要处理高并发、分布式锁等问题的开发场景。
111 38
|
16天前
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
51 6
|
19天前
|
NoSQL Java 微服务
2025 年最新 Java 面试从基础到微服务实战指南全解析
《Java面试实战指南:高并发与微服务架构解析》 本文针对Java开发者提供2025版面试技术要点,涵盖高并发电商系统设计、微服务架构实现及性能优化方案。核心内容包括:1)基于Spring Cloud和云原生技术的系统架构设计;2)JWT认证、Seata分布式事务等核心模块代码实现;3)数据库查询优化与高并发处理方案,响应时间从500ms优化至80ms;4)微服务调用可靠性保障方案。文章通过实战案例展现Java最新技术栈(Java 17/Spring Boot 3.2)的应用.
76 9