目录
🥪下面是一个使用Java线程池处理IO操作的示例代码,可以提高并发性能和响应速度:
🥪下面是一个使用Fork/Join框架处理CPU密集型任务的示例代码:
🥪前言:
记录笔记
🥪下面是一个使用Java线程池处理IO操作的示例代码,可以提高并发性能和响应速度:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class IOThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
executorService.submit(() -> {
// 处理每一行数据的逻辑
System.out.println(Thread.currentThread().getName() + ": " + line);
});
}
} catch (IOException e) {
e.printStackTrace();
}
executorService.shutdown();
}
}
- 在上面的代码中,我们使用了Java线程池来处理读取文件的IO操作。我们使用了一个固定大小的线程池,可以同时处理10个任务。我们使用了try-with-resources语句来自动关闭文件流。在读取文件的每一行时,我们将其提交给线程池处理,从而提高程序的并发性能和响应速度。
🥪示例代码优化:
-
使用线程池的预定义工厂方法:Java提供了一些预定义的线程池工厂方法,例如Executors.newFixedThreadPool()、Executors.newCachedThreadPool()、Executors.newSingleThreadExecutor()等。这些工厂方法可以根据不同的场景选择不同的线程池类型,从而提高程序的性能和可维护性。
-
使用线程池的拒绝策略:当线程池中的线程数量达到最大值时,新的任务将被拒绝。可以使用线程池的拒绝策略来处理这种情况,例如AbortPolicy、CallerRunsPolicy、DiscardPolicy、DiscardOldestPolicy等。这些策略可以根据不同的场景选择不同的处理方式,从而提高程序的可靠性和可维护性。
-
使用CompletableFuture来处理异步任务:Java 8引入了CompletableFuture类,可以方便地处理异步任务。可以使用CompletableFuture来替代线程池,从而提高程序的可读性和可维护性。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.*;
public class IOThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
CompletableFuture.runAsync(() -> {
// 处理每一行数据的逻辑
System.out.println(Thread.currentThread().getName() + ": " + line);
}, executorService).exceptionally(e -> {
e.printStackTrace();
return null;
});
}
} catch (IOException e) {
e.printStackTrace();
}
executorService.shutdown();
}
}
- 在上面的代码中,我们使用了Java 8的CompletableFuture类来处理异步任务。我们使用了线程池的预定义工厂方法来创建线程池。在处理每一行数据时,我们使用CompletableFuture.runAsync()方法来提交异步任务,并将其与线程池关联。我们还使用了CompletableFuture.exceptionally()方法来处理异常情况
🥪依赖:
上面的线程池示例代码没有使用任何第三方库,只使用了Java标准库中的类和接口,因此没有任何依赖。但是,如果您使用了Java 8的CompletableFuture类来处理异步任务,则需要Java 8及以上版本的JDK。
🥪java线程池处理CPU密集型任务
- 对于CPU密集型任务,线程池并不能提高程序的并发性能,因为这种任务需要大量的CPU资源,而线程池中的线程数量是有限的。如果线程池中的线程数量小于CPU核心数,那么线程池并不能充分利用CPU资源,反而会增加线程切换的开销,降低程序的性能。
- 对于CPU密集型任务,更好的做法是使用并行流或者Fork/Join框架来处理。这些框架可以将任务分解成多个子任务,并将子任务分配给多个线程执行,从而充分利用CPU资源,提高程序的并发性能。
🥪下面是一个使用Fork/Join框架处理CPU密集型任务的示例代码:
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class CPUThreadPoolDemo {
public static void main(String[] args) {
int[] data = new int[1000000];
for (int i = 0; i < data.length; i++) {
data[i] = i;
}
ForkJoinPool forkJoinPool = new ForkJoinPool();
long result = forkJoinPool.invoke(new SumTask(data, 0, data.length));
System.out.println(result);
}
static class SumTask extends RecursiveTask<Long> {
private static final int THRESHOLD = 10000;
private int[] data;
private int start;
private int end;
public SumTask(int[] data, int start, int end) {
this.data = data;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if (end - start <= THRESHOLD) {
long sum = 0;
for (int i = start; i < end; i++) {
sum += data[i];
}
return sum;
} else {
int mid = (start + end) / 2;
SumTask leftTask = new SumTask(data, start, mid);
SumTask rightTask = new SumTask(data, mid, end);
leftTask.fork();
rightTask.fork();
return leftTask.join() + rightTask.join();
}
}
}
}
- 在上面的代码中,我们使用了Fork/Join框架来处理CPU密集型任务。我们将任务分解成多个子任务,并将子任务分配给多个线程执行。在处理每个子任务时,我们使用了递归的方式来分解任务,直到任务的大小小于一个阈值。这种方式可以充分利用CPU资源,提高程序的并发性能。
🥪实现逻辑:
-
main()方法:在主线程中创建一个ForkJoinPool对象,并将任务提交给该线程池处理。在处理完任务后,输出任务的结果。
-
SumTask类:继承自RecursiveTask类,用于计算数组中所有元素的和。如果任务的大小小于一个阈值,则直接计算任务的结果;否则,将任务分解成两个子任务,并将子任务分配给不同的线程执行。在处理完子任务后,将子任务的结果合并起来,得到任务的结果。
-
compute()方法:重写了RecursiveTask类的compute()方法,用于计算任务的结果。如果任务的大小小于一个阈值,则直接计算任务的结果;否则,将任务分解成两个子任务,并将子任务分配给不同的线程执行。在处理完子任务后,将子任务的结果合并起来,得到任务的结果。
-
THRESHOLD常量:用于指定任务的大小阈值。如果任务的大小小于该阈值,则直接计算任务的结果;否则,将任务分解成两个子任务,并将子任务分配给不同的线程执行。