Java线程池练习题

1:创建核心线程数为5的固定线程池

java 复制代码
package com.example.exerciseThreadPool;

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

public class FixedThreadPoolDemo {
    public static void main(String[] args) {
        //1.创建核心线程数为5的固定线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);

        //2.提交10个任务
        for (int i = 1; i <= 10; i++) {
            final int taskId = i;
            executor.submit(() -> {
                System.out.println("任务" + taskId + "开始执行,线程:" + Thread.currentThread().getName());
                try {
                    //模拟耗时操作
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("任务" + taskId + "执行完毕");
            });
        }

        //3.关闭线程池
        executor.shutdown();
        try {
            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
    }
}

2:自定义线程池行为验证,深入理解corePoolSize,maximumPoolSize,workQueue和拒绝策略的关系

java 复制代码
package com.example.exerciseThreadPool;

import java.util.concurrent.*;

public class ThreadPoolParamsDemo {
    //自定义线程池行为验证,深入理解corePoolSize,maximumPoolSize,workQueue和拒绝策略的关系
    public static void main(String[] args) {
        //配置参数
        int corePoolSize = 2;
        int maximumPoolSize = 4;
        long keepAliveTime = 60;
        TimeUnit unit = TimeUnit.SECONDS;
        //容量为2的有界队列
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        //默认拒绝策略:抛出异常
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);

        System.out.println("---开始提交任务---");
        for (int i = 1; i <= 8; i++) {
            final int taskId = i;
            try {
                executor.execute(() -> {
                    System.out.println("任务" + taskId + "正在运行,线程" + Thread.currentThread().getName());
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                });
                System.out.println("任务" + taskId + "已提交");
            } catch (RejectedExecutionException e) {
                System.out.println("任务" + taskId + "被拒绝" + e.getMessage());
            }
        }
        executor.shutdown();
    }
}

3:监控线程池状态,获取运行时数据

java 复制代码
package com.example.exerciseThreadPool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPoolMonitorDemo {
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2));

        //提交一些事务
        for (int i = 0; i < 6; i++) {
            executor.submit(() -> {
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {

                }
            });
        }

        //短暂等待后打印状态
        TimeUnit.MILLISECONDS.sleep(500);

        System.out.println("活跃线程数" + executor.getActiveCount());
        System.out.println("当前线程池大小" + executor.getPoolSize());
        System.out.println("队列等待任务数" + executor.getQueue().size());
        System.out.println("已完成任务数" + executor.getCompletedTaskCount());
        executor.shutdownNow();
    }
}

4:多线程抢红包(线程安全),结合线程池与锁机制解决资源竞争

java 复制代码
package com.example.exerciseThreadPool;

import java.math.BigDecimal;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;

public class RedPacketDemo {
    //多线程抢红包(线程安全),结合线程池与锁机制解决资源竞争
    private static BigDecimal totalAmount = new BigDecimal("10.00");
    private static final ReentrantLock lock = new ReentrantLock();
    private static int remainingPeople = 10;

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);

        for (int i = 1; i <= 10; i++) {
            final int personId = i;
            executor.submit(() -> {
                lock.lock();
                try {
                    if (remainingPeople > 0) {
                        BigDecimal amount;
                        if (remainingPeople == 1) {
                            // 最后一个人拿走剩余所有
                            amount = totalAmount;
                        } else {
                            //随机金额逻辑简化:每人至少0.01,最多剩余金额的均值*2
                            BigDecimal max = totalAmount.divide(new BigDecimal(remainingPeople), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("2"));
                            //简单模拟:取剩余金额的10%-20%作为随机范围,此处简化为固定比例演示
                            double randomRatio = Math.random() * 0.1 + 0.05;
                            amount = totalAmount.multiply(new BigDecimal(randomRatio)).setScale(2, BigDecimal.ROUND_HALF_DOWN);

                            //确保不超过剩余金额且不低于0.01
                            if (amount.compareTo(totalAmount) > 0) {
                                amount = totalAmount;
                            }
                            if (amount.compareTo(new BigDecimal("0.01")) < 0) {
                                amount = new BigDecimal("0.01");
                            }
                        }

                        totalAmount = totalAmount.subtract(amount);

                        remainingPeople--;
                        System.out.println("用户" + personId + "抢到" + amount + ",剩余" + totalAmount);
                    }
                } finally {
                    lock.unlock();
                }
            });
        }
        executor.shutdown();
    }
}

注意事项:

1:关闭线程池:务必在程序结束前调用shutdown()或shutdownNow(),否则JVM可能无法退出。

2:避免OOM:生产环境使用ThreadPoolExecutor构造函数并指定有界队列。

3:异常处理:在线程池任务中抛出的未捕获异常不会传播到主线程,建议在任务内部进行try-catch处理,或通过Thread.UncaughtExceptionHandler进行全局捕获。