例1

/**
 * 问题
 * 这段代码的主要问题在于使用了synchronized关键字来保证count变量的线程安全,这种方式会导致所有线程都竞争同一个锁,
 * 从而降低程序的并发性能。我们可以使用AtomicInteger类来代替synchronized关键字,从而实现更高效的线程安全计数。
 * 优化后的代码如ThreadPoolDemo02所示:
 */
public class ThreadPoolDemo01 {
    private static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 1000; j++) {
                executorService.submit(() -> {
                    synchronized (ThreadPoolDemo01.class) {
                        count++;
                    }
                });
            }
        }
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.MINUTES);
        System.out.println("Final count: " + count);
    }
}

例2

/**
 * 在这个示例中,我们使用AtomicInteger类来代替synchronized关键字,从而实现更高效的线程安全计数。
 * AtomicInteger类使用了CAS算法(Compare-And-Swap,比较并交换),可以在不使用锁的情况下实现线程安全的自增操作。
 * 通过使用AtomicInteger类,我们可以避免线程竞争同一个锁的情况,提高程序的并发性能。
 *
 * 问题
 * 1.使用ThreadPoolExecutor类创建线程池:ThreadPoolExecutor类提供了更加灵活的线程池实现,可以根据需要动态调整线程池的大小,避免线程饥饿的情况。
 * 可以替换Executors.newFixedThreadPool()方法创建的固定大小线程池。
 * 2.将计数器和线程池分离:在这个示例中,计数器和线程池都定义在了ThreadPoolDemo02类中。
 * 这样做会导致计数器和线程池的生命周期耦合在一起,不利于代码的维护和优化。
 * 可以将计数器和线程池分离,将计数器定义在一个独立的类中,从而提高代码的可维护性和可重用性。
 */
public class ThreadPoolDemo02 {
    private final LongAdder count = new LongAdder();
    public void increment() {
        count.increment();
    }
    public long getCount() {
        return count.longValue();
    }
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ThreadPoolDemo02 demo02 = new ThreadPoolDemo02();
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 1000; j++) {
                executorService.submit(demo02::increment);
            }
        }
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.MINUTES);
        System.out.println("Final count: " + demo02.getCount());
    }
}

例3

/**
 * 在这个示例中,我们将计数器和线程池分离开来,将计数器定义在了一个独立的类中,从而提高了代码的可维护性和可重用性。
 * 同时,我们使用ThreadPoolExecutor类创建了更加灵活的线程池,并将其作为参数传递给了ExecutorService接口的实现类。
 * 通过这种方式,我们可以动态调整线程池的大小,避免线程饥饿的情况。
 *
 * 问题
 * 1.使用try-with-resources语句:ExecutorService接口实现类返回的线程池都是需要手动关闭的,可以使用try-with-resources语句自动关闭线程池。
 * 2.使用Lambda表达式创建线程池任务:在这个示例中使用了Method Reference的方式创建线程池任务,
 * 可以使用Lambda表达式来代替Method Reference,更加简洁易懂。
 */
public class ThreadPoolDemo03 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        ExecutorService executorService = new ThreadPoolExecutor(
            10, 10, 0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>());
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 1000; j++) {
                executorService.submit(counter::increment);
            }
        }
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.MINUTES);
        System.out.println("Final count: " + counter.getCount());
    }
}
public class Counter {
    private final LongAdder count = new LongAdder();
    public void increment() {
        count.increment();
    }
    public long getCount() {
        return count.longValue();
    }
}

例4

/**
 * 在这个示例中,我们使用try-with-resources语句自动关闭了线程池,同时使用Lambda表达式代替了Method Reference的方式创建线程池任务,更加简洁易懂。
 * 此外,我们还在awaitTermination()方法中捕获了InterruptedException异常,并重新设置了线程的中断状态,以保证线程正确退出。
 *
 * 问题
 * 1.将线程池的参数使用静态常量或配置文件来配置,以方便后续的修改。
 * 2.在创建线程池时,使用ThreadFactory来命名线程池中的线程,以方便调试和排查问题。
 */
public class ThreadPoolDemo04 {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        ExecutorService executorService = new ThreadPoolExecutor(
            10, 10, 0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>());
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 1000; j++) {
                executorService.submit(counter::increment);
            }
        }
        executorService.shutdown();
        try {
            executorService.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("Final count: " + counter.getCount());
    }
}
public class Counter {
    private final LongAdder count = new LongAdder();
    public void increment() {
        count.increment();
    }
    public long getCount() {
        return count.longValue();
    }
}

例5

/**
 * 我们将线程池的参数使用静态常量来配置,方便后续的修改。同时,在创建线程池时,我们使用ThreadFactory来命名线程池中的线程,以方便调试和排查问题。
 * 这样优化后的代码更加灵活,易于维护。
 *
 * 问题
 * 1.使用CompletableFuture来组合线程池任务并获取结果,以便更好地控制任务的执行顺序和错误处理。
 * 2.使用ThreadLocal来避免多个线程同时访问计数器对象带来的性能问题。
 */
public class ThreadPoolDemo05 {
    private static final int THREAD_POOL_SIZE = 10;
    private static final int TASK_COUNT = 10000;
    private static final int AWAIT_TERMINATION_TIME = 1;
    private static final TimeUnit AWAIT_TERMINATION_TIME_UNIT = TimeUnit.MINUTES;
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        ExecutorService executorService = new ThreadPoolExecutor(
            THREAD_POOL_SIZE, THREAD_POOL_SIZE, 0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(),
            new NamedThreadFactory("ThreadPoolDemo"));
        for (int i = 0; i < THREAD_POOL_SIZE; i++) {
            for (int j = 0; j < TASK_COUNT; j++) {
                executorService.submit(counter::increment);
            }
        }
        executorService.shutdown();
        try {
            executorService.awaitTermination(AWAIT_TERMINATION_TIME, AWAIT_TERMINATION_TIME_UNIT);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("Final count: " + counter.getCount());
    }
}
public class Counter {
    private final LongAdder count = new LongAdder();
    public void increment() {
        count.increment();
    }
    public long getCount() {
        return count.longValue();
    }
}
public class NamedThreadFactory implements ThreadFactory {
    private final String namePrefix;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    public NamedThreadFactory(String namePrefix) {
        this.namePrefix = namePrefix;
    }
    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, namePrefix + "-thread-" + threadNumber.getAndIncrement());
    }
}

例6

/**
 * 使用CompletableFuture来组合线程池任务并获取结果,以便更好地控制任务的执行顺序和错误处理
 * 同时,我们使用ThreadLocal来避免多个线程同时访问计数器对象带来的性能问题。这样优化后的代码更加高效和可读。
 */
public class ThreadPoolDemo06 {
    private static final int THREAD_POOL_SIZE = 10;
    private static final int TASK_COUNT = 1000;
    private static final int AWAIT_TERMINATION_TIME = 1;
    private static final TimeUnit AWAIT_TERMINATION_TIME_UNIT = TimeUnit.MINUTES;
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Counter01 counter = new Counter01();
        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE, new NamedThreadFactory("ThreadPoolDemo"));
        List<CompletableFuture<Void>> futureList = new ArrayList<>();
        for (int i = 0; i < THREAD_POOL_SIZE; i++) {
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                for (int j = 0; j < TASK_COUNT; j++) {
                    counter.increment();
                }
            }, executorService);
            futureList.add(future);
        }
        CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]))
            .exceptionally(ex -> {
                ex.printStackTrace();
                return null;
            }).get();
        executorService.shutdown();
        try {
            executorService.awaitTermination(AWAIT_TERMINATION_TIME, AWAIT_TERMINATION_TIME_UNIT);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("Final count: " + counter.getCount());
    }
}
public class Counter01 {
    private final ThreadLocal<LongAdder> count = ThreadLocal.withInitial(LongAdder::new);
    public void increment() {
        count.get().increment();
    }
    public long getCount() {
        return count.get().longValue();
    }
}
public class NamedThreadFactory implements ThreadFactory {
    private final String namePrefix;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    public NamedThreadFactory(String namePrefix) {
        this.namePrefix = namePrefix;
    }
    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, namePrefix + "-thread-" + threadNumber.getAndIncrement());
    }
}