4、高并发编程-线程池

本文详细介绍了Java中的几种线程池,包括FixedThreadPool、CachedThreadPool、SingleThreadExecutor、ScheduledThreadPool和ForkJoinPool。讲解了它们的特点、使用场景及执行结果,如FixedThreadPool的固定容量和生命周期,CachedThreadPool的自动扩容与线程回收,以及如何通过ThreadPoolExecutor实现自定义线程池。同时,文章还展示了如何利用线程池进行串行计算和并行计算的性能对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、FixedThreadPool

固定容量的线程池,线程池默认的容量上限是Integer.MAX_VALUE。常见的线程池容量:pc=200,服务器=1000~10000

FixedThreadPool一般由Executors(工具类)来获取,并可以指定线程池的容量。线程池是一个进程级的重量级资源。默认的生命周期和JVM一致。当开启线程池后,知道JVM关闭为止,是线程池的默认生命周期。可以通过调用shutdown方法来让线程池执行完所有的任务后,自动关闭。

Executor是线程池顶级接口,定义了execute(Runnable) 方法。调用的时候提供Runnable的实现,线程池通过这个线程去执行这个Runnable。

ExecutorService是Executro的子接口。

下面的代码定义了具有5个线程的线程池,初始化6个线程去运行任务,shutdown并不是马上关闭,是等到线程池中的任务执行结束后再关闭

package com.sunyou.p5;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/* 
 * 容量固定的线程池。活动状态和线程池容量是有上限的线程池。 
 *  所有的线程池中,都有一个任务队列。
 *  使用的是 BlockingQueue<Runnable>作为任务的载体。 
 *  当任务数量大于线程池容量的时候,没有运行的任务保存在任务队列中,当线程有空闲的,自动从队列中取出任务执行
 *  
 *  常见的线程池容量 pc-20 服务器 1000-10000
 */
public class FixedThreadPoolTest {
	private static ExecutorService service = Executors.newFixedThreadPool(5);
	public static void main(String[] args) throws Exception {
		for(int i = 0; i < 6; i++) {
			service.execute(new Runnable() {
				@Override
				public void run() {
					System.out.println(Thread.currentThread().getName()+"正在执行");
				}
			});
		}
		System.out.println(service);//service如果不关,程序会一直运行
		System.out.println(service.isShutdown());
		System.out.println(service.isTerminated());
		service.shutdown();
		TimeUnit.SECONDS.sleep(2);
		System.out.println(service);
		System.out.println(service.isShutdown());
		System.out.println(service.isTerminated());
	}
	
}

运行结果

pool-1-thread-1正在执行
pool-1-thread-5正在执行
pool-1-thread-1正在执行
pool-1-thread-4正在执行
pool-1-thread-3正在执行
pool-1-thread-2正在执行
java.util.concurrent.ThreadPoolExecutor@42a57993[Running, pool size = 5, active threads = 1, queued tasks = 0, completed tasks = 5]
false
false
java.util.concurrent.ThreadPoolExecutor@42a57993[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]
true
true

2、Future

未来结果,代表线程任务执行结束后的结果。获取线程执行结果的方式是通过get方法获取。该方法会阻塞等待线程执行结束,并得到返回结果。如果该方法传入参数,阻塞固定时长,等待线程执行结束后的结果,如果等待过程中线程未执行结束会抛出异常。

package com.sunyou.p6;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class FutureTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService service = Executors.newFixedThreadPool(1);
		Future<String> future = service.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				System.out.println("call method is start");
				TimeUnit.SECONDS.sleep(1);
				return Thread.currentThread().getName()+" is over";
			}
		});
		System.out.println(future);
		System.out.println(future.isDone());
		System.out.println("future的返回值为 "+future.get());
		System.out.println(future.isDone());
	}
}

执行结果

java.util.concurrent.FutureTask@33909752
call method is start
false
future的返回值为 pool-1-thread-1 is over
true

3、使用FixedThreadPool来进行串行计算和并行计算时间

下列代码计算2000000以内的质数,并将其添加到list集合中。在并行过程中,将2000000这个数进行划分,划分为5各组。每个组开一个线程进行计算。最后比较二者的时间。

package com.sunyou.p6;

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/*
 * 使用FixedThreadPool来测试并行计算和串行计算效率
 */
public class ParallelComputingVSSerialComputing {
	static class MyTask implements Callable<ArrayList<Integer>>{
		int start,end;
		MyTask(int start, int end){
			this.start = start;
			this.end = end;
		}
		@Override
		public ArrayList<Integer> call() throws Exception {
			ArrayList<Integer> list = new ArrayList<>();
			boolean flag = true;
			//找质数
			for(int i = start; i <= end; i++) {
				for(int j = 2; j <= Math.sqrt(i); j++) {
					if(i % j == 0) {
						flag = false;
						break;
					}
				}
				if(flag) {
					list.add(i);
				}
				flag = true;
			}
			return list;
		}
	}
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//串行计算
		long start = System.currentTimeMillis();
		serialComputing(1,2000000);
		long end = System.currentTimeMillis();
		System.out.println("Serial Computing time is " + (end - start)  + " ms");
		
		//多个task并行计算
		ExecutorService service = Executors.newFixedThreadPool(5);
		Future<ArrayList<Integer>> f1 = service.submit(new MyTask(1,60000));
		Future<ArrayList<Integer>> f2 = service.submit(new MyTask(60001, 110000));
		Future<ArrayList<Integer>> f3 = service.submit(new MyTask(110001, 150000));
		Future<ArrayList<Integer>> f4 = service.submit(new MyTask(150001, 180000));
		Future<ArrayList<Integer>> f5 = service.submit(new MyTask(180001, 200000));
		start = System.currentTimeMillis();
		f1.get();
		f2.get();
		f3.get();
		f4.get();
		f5.get();
		end = System.currentTimeMillis();
		System.out.println("Parallel Computing time is " + (end - start) + " ms");
		
	}
	public static void serialComputing(int start, int end) {
		ArrayList<Integer> list = new ArrayList<>();
		boolean flag = true;
		//找质数
		for(int i = start; i <= end; i++) {
			for(int j = 2; j <= Math.sqrt(i); j++) {
				if(i % j == 0) {
					flag = false;
					break;
				}
			}
			if(flag) {
				list.add(i);
			}
			flag = true;
		}
	}
}

执行结果

Serial Computing time is 1260 ms
Parallel Computing time is 20 ms

4、CachedThreadPool

缓存的线程池,容量不限(Integer.MAX_VALUE)。自动扩容,如果线程池中的线程数量不满足任务执行,创建新的线程。每次有新任务无法即时处理的时候都会创建新的线程。当线程池中的线程空闲时长达到一定临界值(默认60s),自动释放线程。

package com.sunyou.p6;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/*
 * 缓存的线程池,容量不限(Integer.MAX_VALUE),自动扩容
 * 如果线程池中的线程数量不满足任务执行,创建新的线程。每次执行新任务无法即时处理
 * 的时候都会创建新的线程。
 * 当线程池中的线程空闲时间超过一定临界值时(默认60s),自动释放线程。
 */
public class CachedThreadPoolTest {
	public static void main(String[] args) throws InterruptedException {
		ExecutorService service = Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++) {
			service.execute(new Runnable() {
				@Override
				public void run() {
					try {
						TimeUnit.SECONDS.sleep(1);
						System.out.println(Thread.currentThread().getName() + "- test");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		System.out.println(service);
		// 默认线程空闲60s自动关闭
		TimeUnit.SECONDS.sleep(70);
		System.out.println(service);
	}
}

执行结果

java.util.concurrent.ThreadPoolExecutor@75b84c92[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
pool-1-thread-3- test
pool-1-thread-1- test
pool-1-thread-4- test
pool-1-thread-2- test
pool-1-thread-5- test
java.util.concurrent.ThreadPoolExecutor@75b84c92[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 5]

5、SingleThreadExecutor

单一容量线程池。保证任务顺序执行。

package com.sunyou.p6;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/*
 * 容量为1的线程池,保证任务顺序执行
 */
public class SingleThreadPoolTest {
	public static void main(String[] args) {
		ExecutorService service = Executors.newSingleThreadExecutor();
		for(int i = 0; i < 5; i++) {
			service.execute(new Runnable() {
				@Override
				public void run() {
					try {
						TimeUnit.SECONDS.sleep(1);
						System.out.println(Thread.currentThread().getName() + "-test");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
	}
}

执行结果

pool-1-thread-1-test
pool-1-thread-1-test
pool-1-thread-1-test
pool-1-thread-1-test
pool-1-thread-1-test

6、ScheduledThreadPool

计划任务线程池,可以根据计划自动执行任务的线程池。计划任务时使用。

package com.sunyou.p6;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/*
 * 计划任务线程池
 */
public class ScheduledThreadPoolTest {
	public static void main(String[] args) {
		ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
		System.out.println(service);
		service.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName()+"-test");
			}
			//会一直执行
		//第一次执行任务的时间  每次任务的时间间隔  时间间隔的单位
		}, 0, 1, TimeUnit.SECONDS);
	}
}

7、ForkJoinPool

分支合并线程池,适合处理复杂任务。线程池中运行的内容必须是ForkJoinTask的子类型(RecursiveTask、RecursiveAction)。task有返回结果,action无返回结果。

package com.sunyou.p6;

import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

/*
 * 分支合并线程池,适合处理复杂任务
 */
public class ForkJoinPoolTest {
	static int[] number = new int[1000000];
	static final int MAX_VALUE = 50000;
	static Random r = new Random();
	//对数组初始化
	static {
		for(int i = 0; i < number.length; i++)
			number[i] = r.nextInt(1000);
	}
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		long start = System.currentTimeMillis();
		long sum = 0;
		for(int i = 0; i < number.length; i++)
			sum += number[i];
		long end = System.currentTimeMillis();
		System.out.println("result is " + sum);
		System.out.println("computing time is " + (end - start) + " ms");
		
		start = System.currentTimeMillis();
		ForkJoinPool pool = new ForkJoinPool();
		Task task = new Task(0,1000000-1);
		ForkJoinTask<Long> future = pool.submit(task);
		sum = future.get();
		end = System.currentTimeMillis();
		System.out.println("result is " + sum);
		System.out.println("computing time is " + (end - start) + " ms");
	}
	
	static class Task extends RecursiveTask<Long>{
		int begin , end;
		Task(int begin, int end){
			this.begin = begin;
			this.end = end;
		}
		@Override
		protected Long compute() {
			long sum = 0;
			if((end - begin) < MAX_VALUE) {
				for(int i = begin; i <= end; i++)
					sum += number[i];
				return sum;
			}else {
				int mid = begin + (end - begin) / 2;
				Task task1 = new Task(begin, mid);
				Task task2 = new Task(mid + 1, end);
				//开启新的任务
				task1.fork();
				task2.fork();
				//将结果合并返回
				return task1.join() + task2.join();
			}
		}
	}
}
result is 499490831
computing time is 10 ms
result is 499490831
computing time is 10 ms

8、ThreadPoolExecutor

线程池底层实现,除了ForkJoinPool外,其他常用的线程池都是使用ThreadPoolExecutor实现的。

package com.sunyou.p6;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/*
 * 线程池底层实现
 */
public class ThreadPoolExecutorTest {
	public static void main(String[] args) {
		//核心容量 最大容量 生命周期(0表示永久) 生命周期时间单位 任务队列
		ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 5, 0, TimeUnit.MILLISECONDS, 
				new LinkedBlockingQueue<>());
		for(int i = 0; i < 6; i++) {
			pool.execute(new Runnable() {
				@Override
				public void run() {
					try {
						TimeUnit.SECONDS.sleep(1);
						System.out.println(Thread.currentThread().getName());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		System.out.println(pool);
		System.out.println(pool.isTerminated());
		System.out.println(pool.isShutdown());
		pool.shutdown();
		try {
			TimeUnit.SECONDS.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(pool);
		System.out.println(pool.isTerminated());
		System.out.println(pool.isShutdown());
		
	}
}

结果

java.util.concurrent.ThreadPoolExecutor@42a57993[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
false
false
pool-1-thread-2
pool-1-thread-4
pool-1-thread-1
pool-1-thread-5
pool-1-thread-3
pool-1-thread-2
java.util.concurrent.ThreadPoolExecutor@42a57993[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]
true
true

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值