使用多线程执行大量任务提高执行效率
一 、执行方法后需要获取返回值
这种获取多线程返回值的方式有很大的缺点,那就是会导致线程阻塞,主线程必须等待该线程获取到返回值后才执行下一个,效率会大大降低。
导入依赖
<!-- // 使用hutool的NamedThreadFactory 线程工厂,主要用来创建线程-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.20</version>
</dependency>
代码
package cn.zzz.idb.stream;
import cn.hutool.core.thread.NamedThreadFactory;
import java.util.*;
import java.util.concurrent.*;
/**
* @Author: hjt
* @Date: 2022/08/20/18:28
* @Description: 使用多线程执行任务
* 线程创建顺序 : 1.核心线程池:判断“核心线程池”是否已满,否,则创建线程执行任务;是,则移交“任务缓存队列”
* 2.任务缓存队列:判断“任务缓存队列”是否已满,否,则将任务存于“任务缓存队列”中;是,则移交“最大线程池”
* 3.最大线程池:判断“最大线程池”是否已满,否,则创建线程执行任务;是,则移交给“线程溢出任务处理策略”
* 4.线程溢出任务处理策略:按照指定的策略来处理无法执行的任务
*/
public class StreamTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 接收结果集
List<Future<String>> futureList = new ArrayList<>();
// 创建有界阻塞队列,防止内存溢出 任务缓存队列,即workQueue,它用来存放等待执行的任务。
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(3);
// 使用hutool的NamedThreadFactory 线程工厂,主要用来创建线程 自定义线程前缀名 是否守护线程 String prefix, boolean isDaemon
ThreadFactory threadFactory = new NamedThreadFactory("测试",false);
// 任务拒绝策略 1 AbortPolicy策略 直接抛异常,阻止系统正常工作 是默认策略
// 2 CallerRunsPolicy策略 只用调用者所在的线程处理任务
// 3 DiscardOldestPolicy策略 丢弃等待队列中最旧的任务,并执行当前任务
// 4 DiscardPolicy策略 直接丢弃任务,但不抛出异常
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
// 核心线程数 < 最大线程数 线程没有任务时的存活时间
ThreadPoolExecutor executor = new ThreadPoolExecutor(2,4,3, TimeUnit.SECONDS,workQueue,threadFactory,handler);
Long start = System.currentTimeMillis();
for (int i = 0; i < 20; i++) {
try{
// 提交任务 submit()方法有一个返回值Future
futureList.add(executor.submit(new Task()));
System.out.println("当前排队线程数:= " + executor.getQueue().size()); // 最大值 为 任务缓存队列 长度
System.out.println("当前活动线程数:= " + executor.getActiveCount()); // 最大值 为 核心线程池数 + 最大线程池数
System.out.println("===============================");
}catch (Exception e){
System.out.println("异常");
}
}
executor.shutdown();
System.out.println("线程结束===============================");
for (Future<String> stringFuture : futureList) {
System.out.println(stringFuture.get());
}
Long end = System.currentTimeMillis();
System.out.println(end-start); // 5 361 10 180 15 139
}
/**
* 无参多线程方法
*/
public static class Task implements Callable<String>{
@Override
public String call() throws Exception {
Thread.sleep(10);
return Thread.currentThread().getName();
}
}
/**
* 传入参数 多线程方法
* 无参构造方法中调用业务方法
*/
public static class Task2 implements Callable<String>{
private String name;
private int age;
public Task2(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String call() throws Exception {
System.out.println("name = " + name);
System.out.println("age = " + age);
return Thread.currentThread().getName();
}
}
}
二 、执行方法后不获取返回值
package cn.zzz.idb.stream;
import cn.hutool.core.thread.NamedThreadFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @Author: hjt
* @Date: 2022/08/20/19:51
* @Description:
*/
public class StreamTest2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建有界阻塞队列,防止内存溢出 任务缓存队列,即workQueue,它用来存放等待执行的任务。
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);
ThreadFactory threadFactory = new NamedThreadFactory("测试",false);
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
// 线程计数器
CountDownLatch countDownLatch = new CountDownLatch(10);
ThreadPoolExecutor executor = new ThreadPoolExecutor(2,3,3, TimeUnit.SECONDS,workQueue,threadFactory,handler);
Long start = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
try{
Task task = new Task();
executor.execute(task);
System.out.println("当前排队线程数:= " + executor.getQueue().size()); // 最大值 为 任务缓存队列 长度
System.out.println("当前活动线程数:= " + executor.getActiveCount()); // 最大值 为 核心线程池数 + 最大线程池数
System.out.println("===============================");
}catch (Exception e){
System.out.println("异常");
}
}
executor.shutdown();
// //当所有线程执行完毕后才继续执行后续代码
// countDownLatch.countDown();
// countDownLatch.await();
System.out.println("线程结束===============================");
Long end = System.currentTimeMillis();
System.out.println(end-start); // 5 361 10 180 15 139
}
/**
* 无参多线程方法
*/
public static class Task implements Runnable{
@Override
public void run() {
try {
Thread.sleep(10);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}