例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());
}
}