这里只举几个线程池newFixedThreadPool实用的列子,想要更深入一些可以去《java线程池之newFixedThreadPool》进行初步了解。

一、被调用的方法

先来三个要被调用的测试方法

1.1 无参数,无返回值

	/**
	 * 无参数,无返回值
	 */
	private void hello01() {
		try {
			Thread.sleep(5000);
			LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello01()完毕,无参数无返回数据,异步执行");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

1.2 无参数,有返回值

	/**
	 * 无参数,有返回值
	 */
	private String hello02() {
		try {
			Thread.sleep(3000);
			LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello02()完毕,无参数有返回数据,需等待线程执行完毕");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// 返回随意的一串字符串
		return "我返回的是随机字符串:" + UUID.randomUUID().toString();
	}

1.3 有参数,无返回值

	/**
	 * 有参数,无返回值
	 */
	private void hello03(String name) {
		try {
			Thread.sleep(5000);
			LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello03()完毕,有参数无返回数据,异步执行");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

1.4 有参数,有返回值

	/**
	 * 有参数,有返回值
	 */
	private String hello04(String name) {
		try {
			Thread.sleep(5000);
			LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello04()完毕,有参数有返回数据,需等待线程执行完毕");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "我返回的是" + name + "的数据";
	}

二、线程池调用

2.1 无参数,无返回值

	/**
	 * 无参数,且不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
	 * execute(Runnable command):
	 * 	将一个Runnable任务提交给线程池执行。该方法将会在ThreadPoolExecutor内部的阻塞队列中插入任务,等待线程池中的线程执行任务。
	 */
	public void test01(){
		ExecutorSerDemo es = new ExecutorSerDemo();
		
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		for (int i = 0; i < 5; i++) {
			// 使用匿名内部类的方式创建一个实现了Runnable接口的对象,并在run()方法中调用es.hello01()方法
//			executorService.execute(new Runnable() {
//				@Override
//				public void run() {
//					es.hello01();
//				}
//			});
			// 建议使用Lambda表达式的方式,更加简洁易读
			executorService.execute(() -> es.hello01());
		}
		
		executorService.shutdown();
		System.out.print("test01()执行完毕,");
	}

执行结果,先输出了执行用时,线程还在异步执行:

巧用线程池newFixedThreadPool _数据

2.2 无参数,有返回值

	/**
	 * 无参数,接收返回数据(需等待线程执行完毕并继续执行后续业务)
	 */
	public void test02() {
		ExecutorSerDemo es = new ExecutorSerDemo();

		ExecutorService executorService = Executors.newFixedThreadPool(3);
		List<Future<String>> list = new ArrayList<>();
		
		for (int i = 0; i < 5; i++) {
			// executorService.submit可以接收返回结果
			Future<String> submit = executorService.submit(()->es.hello02());
			list.add(submit);
		}
		
		List<String> dataList = new ArrayList<>();
		try {
			// 接收返回数据
			for (Future<String> future : list) {
				String str = future.get();
				dataList.add(str);
			}
		} catch (Exception e) {
			// 如果发生异常则结束所有线程
			for (Future<?> future : list) {
				future.cancel(true);
			}
		}
		
		
		// 关闭线程池
		executorService.shutdown();
		
		for (int i = 0; i < dataList.size(); i++) {
			System.err.println("接收到的数据:" + dataList.get(i));
		}
		System.out.print("test02()执行完毕,");
	}

执行结果,等待线程执行结束并获取返回结果,再输出执行用时:

巧用线程池newFixedThreadPool _List_02

2.3 有参数,无返回值

	/**
	 * 有参数,但不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
	 */
	public void test03() {
		List<String> nameList = new ArrayList<>();
		nameList.add("小橙");
		nameList.add("小红");
		nameList.add("小青");
		nameList.add("小白");
		nameList.add("小紫");
		
		ExecutorSerDemo es = new ExecutorSerDemo();
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		
		for (int i = 0; i < nameList.size(); i++) {
			// executorService.submit可以接收返回结果
			int num = i;
			executorService.execute(()->es.hello03(nameList.get(num)));
		}
		
		// 关闭线程池
		executorService.shutdown();
		System.out.print("test03()执行完毕,");
	}

执行结果,先输出了执行用时,线程还在异步执行:

巧用线程池newFixedThreadPool _数据_03

2.4 有参数,有返回值

	/**
	 * 有参数,接收返回数据,等待线程执行完毕再继续执行后续业务
	 */
	public void test04() {
		List<String> nameList = new ArrayList<>();
		nameList.add("张三");
		nameList.add("李四");
		nameList.add("王五");
		nameList.add("赵六");
		nameList.add("林七");
		
		ExecutorSerDemo es = new ExecutorSerDemo();

		ExecutorService executorService = Executors.newFixedThreadPool(3);
		List<Future<String>> list = new ArrayList<>();
		
		for (int i = 0; i < nameList.size(); i++) {
			// executorService.submit可以接收返回结果
			int num = i;
			Future<String> submit = executorService.submit(()->es.hello04(nameList.get(num)));
			list.add(submit);
		}
		
		List<String> dataList = new ArrayList<>();
		try {
			// 接收返回数据
			for (Future<String> future : list) {
				String str = future.get();
				dataList.add(str);
			}
		} catch (Exception e) {
			for (Future<?> future : list) {
				future.cancel(true);
			}
		}
		
		
		// 关闭线程池
		executorService.shutdown();
		
		for (int i = 0; i < dataList.size(); i++) {
			System.err.println(dataList.get(i));
		}
		
		System.out.print("test04()执行完毕,");
	}

执行结果,等待线程执行结束并获取返回结果,再输出执行用时:

巧用线程池newFixedThreadPool _System_04

三、总结

3.1 不接收返回值

使用:executorService.execute()

3.2 接收返回值

使用:executorService.submit()

3.3 不需要等待线程执行结果(异步)

使用:executorService.execute()

3.4 需要等待线程执行结果(阻塞)

使用:executorService.submit()

四、测试类

代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.StopWatch;

public class ExecutorSerDemo {
	private static final Logger LOG = LogManager.getLogger();
	
	public static void main(String[] args) {
		ExecutorSerDemo es = new ExecutorSerDemo();
		StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
//		es.test01();
//		es.test02();
//		es.test03();
		es.test04();
		
		stopWatch.stop();
		// 统计用时
		long[] de = formatDurationByMillis(stopWatch.getTotalTimeMillis());
		
		System.out.println("用时:" + de[0] + "天" + de[1] + "小时" + de[2] + "分" + de[3] + "秒" + de[4] + "毫秒");
	}
	
	
	/**
	 * 无参数,且不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
	 * execute(Runnable command):
	 * 	将一个Runnable任务提交给线程池执行。该方法将会在ThreadPoolExecutor内部的阻塞队列中插入任务,等待线程池中的线程执行任务。
	 */
	public void test01(){
		ExecutorSerDemo es = new ExecutorSerDemo();
		
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		for (int i = 0; i < 5; i++) {
			// 使用匿名内部类的方式创建一个实现了Runnable接口的对象,并在run()方法中调用es.hello01()方法
//			executorService.execute(new Runnable() {
//				@Override
//				public void run() {
//					es.hello01();
//				}
//			});
			// 建议使用Lambda表达式的方式,更加简洁易读
			executorService.execute(() -> es.hello01());
		}
		
		executorService.shutdown();
		System.out.print("test01()执行完毕,");
	}
	
	/**
	 * 无参数,接收返回数据(需等待线程执行完毕并继续执行后续业务)
	 */
	public void test02() {
		ExecutorSerDemo es = new ExecutorSerDemo();

		ExecutorService executorService = Executors.newFixedThreadPool(3);
		List<Future<String>> list = new ArrayList<>();
		
		for (int i = 0; i < 5; i++) {
			// executorService.submit可以接收返回结果
			Future<String> submit = executorService.submit(()->es.hello02());
			list.add(submit);
		}
		
		List<String> dataList = new ArrayList<>();
		try {
			// 接收返回数据
			for (Future<String> future : list) {
				String str = future.get();
				dataList.add(str);
			}
		} catch (Exception e) {
			// 如果发生异常则结束所有线程
			for (Future<?> future : list) {
				future.cancel(true);
			}
		}
		
		
		// 关闭线程池
		executorService.shutdown();
		
		for (int i = 0; i < dataList.size(); i++) {
			System.err.println("接收到的数据:" + dataList.get(i));
		}
		System.out.print("test02()执行完毕,");
	}
	
	/**
	 * 有参数,但不接收返回数据(无需等待线程执行完毕再执行后续业务,也就是异步执行)
	 */
	public void test03() {
		List<String> nameList = new ArrayList<>();
		nameList.add("小橙");
		nameList.add("小红");
		nameList.add("小青");
		nameList.add("小白");
		nameList.add("小紫");
		
		ExecutorSerDemo es = new ExecutorSerDemo();
		ExecutorService executorService = Executors.newFixedThreadPool(3);
		
		for (int i = 0; i < nameList.size(); i++) {
			// executorService.submit可以接收返回结果
			int num = i;
			executorService.execute(()->es.hello03(nameList.get(num)));
		}
		
		// 关闭线程池
		executorService.shutdown();
		System.out.print("test03()执行完毕,");
	}
	
	/**
	 * 有参数,接收返回数据,等待线程执行完毕再继续执行后续业务
	 */
	public void test04() {
		List<String> nameList = new ArrayList<>();
		nameList.add("张三");
		nameList.add("李四");
		nameList.add("王五");
		nameList.add("赵六");
		nameList.add("林七");
		
		ExecutorSerDemo es = new ExecutorSerDemo();

		ExecutorService executorService = Executors.newFixedThreadPool(3);
		List<Future<String>> list = new ArrayList<>();
		
		for (int i = 0; i < nameList.size(); i++) {
			// executorService.submit可以接收返回结果
			int num = i;
			Future<String> submit = executorService.submit(()->es.hello04(nameList.get(num)));
			list.add(submit);
		}
		
		List<String> dataList = new ArrayList<>();
		try {
			// 接收返回数据
			for (Future<String> future : list) {
				String str = future.get();
				dataList.add(str);
			}
		} catch (Exception e) {
			for (Future<?> future : list) {
				future.cancel(true);
			}
		}
		
		
		// 关闭线程池
		executorService.shutdown();
		
		for (int i = 0; i < dataList.size(); i++) {
			System.err.println(dataList.get(i));
		}
		
		System.out.print("test04()执行完毕,");
	}
	
	// ------------------- private method -------------------
	/**
	 * 无参数,无返回值
	 */
	private void hello01() {
		try {
			Thread.sleep(5000);
			LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello01()完毕,无参数无返回数据,异步执行");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 无参数,有返回值
	 */
	private String hello02() {
		try {
			Thread.sleep(3000);
			LOG.info("线程[" + Thread.currentThread().getName() + "]执行方法hello02()完毕,无参数有返回数据,需等待线程执行完毕");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// 返回随意的一串字符串
		return "我返回的是随机字符串:" + UUID.randomUUID().toString();
	}
	
	/**
	 * 有参数,无返回值
	 */
	private void hello03(String name) {
		try {
			Thread.sleep(5000);
			LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello03()完毕,有参数无返回数据,异步执行");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 有参数,有返回值
	 */
	private String hello04(String name) {
		try {
			Thread.sleep(5000);
			LOG.info(name + "你好,线程[" + Thread.currentThread().getName() + "]执行方法hello04()完毕,有参数有返回数据,需等待线程执行完毕");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return "我返回的是" + name + "的数据";
	}
	
	/**
	 * <h5>功能:根据毫秒数来格式化持续时间</h5>
	 * 
	 * @param millis 毫秒数
	 * @return long[] 返回值为:{天, 时, 分, 秒, 毫秒}
	 */
	private static long[] formatDurationByMillis(long millis) {
		long day = TimeUnit.MILLISECONDS.toDays(millis);
		long hour = TimeUnit.MILLISECONDS.toHours(millis) % 24;
		long minute = TimeUnit.MILLISECONDS.toMinutes(millis) % 60;
		long seconds = TimeUnit.MILLISECONDS.toSeconds(millis) % 60;
		millis = millis % 1000;

		long[] times = { day, hour, minute, seconds, millis };
		return times;
	}
}

五、应用

将一个大的集合分割成多个小集合,然后使用线程池并发执行,可以有效减少总体用时时间。List数据分割可以参考《List集合分组(大List分割成多个小List)》

    public void test(List<Map<String, Object>> maps) {
        List<Future<Boolean>> list = new ArrayList<>();

        System.out.println("多线程任务执行开始");

        // 将List集合进行分组
        List<List<Map<String, Object>>> dataList = splitList(maps, 20);
        if (!dataList.isEmpty()) {
            ExecutorService service = Executors.newFixedThreadPool(threadCount);
            for (int i = 0; i < dataList.size(); i++) {
                int k = i;
                Future<Boolean> submit = service.submit(() -> selectAll(dataList.get(k)));
                list.add(submit);
            }
            for (Future<Boolean> future : list) {
                future.get();
                future.cancel(true);
            }
            service.shutdown();
        }
        System.out.println("多线程任务执行完毕");
    }

    /**
     * <h5>描述:将List集合进行分组<h5>
     */
    private static <T> List<List<T>> splitList(List<T> oldList, int batchSize) {
        if (batchSize < 1) {
            return null;
        }
        List<List<T>> result = new ArrayList<>();
        int size = oldList.size();
        int count = (size + batchSize - 1) / batchSize;
        for (int i = 0; i < count; i++) {
            int fromIndex = i * batchSize;
            int toIndex = (i + 1) * batchSize > size ? size : (i + 1) * batchSize;
            List<T> subList = oldList.subList(fromIndex, toIndex);
            result.add(subList);
        }
        return result;
    }