线程池

mac2025-03-16  13

线程池

1.线程池概念

频繁创建和销毁线程很耗费资源,利用线程池可以重复利用线程资源

1.请求交给核心线程 2.核心满了,交给队列 3.队列满了,交给临时线程 临时满了,交给拒绝服务器

2.自定义线程池

package cn.tedu.pool; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class PoolDemo { public static void main(String[] args) { /* * 创建线程池 * 参一:核心线程数,一旦创建就不销毁了 * 参二:最大线程数,核心线程+临时线程数<=最大线程数 * 参三:存活时间,临时线程的存活时间,当临时线程空闲超过存活时间,则进行销毁 * 参四:时间单位 * 参五:队列,核心线程满了,请求放入队列 * 参六:拒绝处理器,当线程池满了,新来的请求交给拒绝处理器 */ ExecutorService es = new ThreadPoolExecutor( 5, 10, 4, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor excutor) { System.out.println("当前线程池已满,请等待"); } }); //关闭线程池,在调用此方法时,线程池将不在接收请求 //此方法并非马上关上线程池,而是等到线程池中的所有线程工作完毕后再关闭 for(int i =0 ;i<14;i++){ //执行启动线程 es.execute(new Run01()); } es.shutdown(); //while(true); /* * 这个池子---大池子,小队列 * 1.无核心线程 * 2.临时线程无限大 * 3.队列只能存一个元素 * 应用场景:高并发,短请求 * 因为如果是长请求,造成线程数过大,而一直得不到销毁,可能造成内存溢出 */ ExecutorService es2 = Executors.newCachedThreadPool(); /* * 小池子,大队列 * 1.全是核心线程,线程数自定义 * 2.没有临时线程,也没有存活时间 * 3.队列无限大 * 应用场景:低并发,长请求,可以缓解高峰压力 * 核心线程无需销毁,所以性能很好 */ ExecutorService es3 = Executors.newFixedThreadPool(10); //也可以自定义线程池,但是注意,不要创建小池子,小队列 } } class Run01 implements Runnable{ public void run() { System.out.println("我来了"); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }

3.常用线程池

/* * 这个池子---大池子,小队列 * 1.无核心线程 * 2.临时线程无限大 * 3.队列只能存一个元素 * 应用场景:高并发,短请求 * 因为如果是长请求,造成线程数过大,而一直得不到销毁,可能造成内存溢出 */ ExecutorService es2 = Executors.newCachedThreadPool(); /* * 小池子,大队列 * 1.全是核心线程,线程数自定义 * 2.没有临时线程,也没有存活时间 * 3.队列无限大 * 应用场景:低并发,长请求,可以缓解高峰压力 * 核心线程无需销毁,所以性能很好 */ ExecutorService es3 = Executors.newFixedThreadPool(10); //也可以自定义线程池,但是注意,不要创建小池子,小队列

4.ScheduledExecutorService-延时线程池

在执行线程时,可以指定延时多久后执行

package cn.tedu.pool; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ScheduledExecutorServiceDemo { public static void main(String[] args) { //定时线程池 ScheduledExecutorService ses = Executors.newScheduledThreadPool(5); /* * 参一:需要执行的线程 * 参二:延时时间,表示延时多久后执行线程 * 参三:时间单位 */ ses.schedule(new Run02(), 5, TimeUnit.SECONDS); } } class Run02 implements Runnable{ public void run() { System.out.println("我来了"); /*try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }*/ } }

5.ForkJoinPool-分叉合并池

如果有一个线程,执行任务量很大,而一个线程,只能由一个cpu的核执行 1.分叉:将任务分解,大的任务拆分成多个小任务 2.合并:将分叉的结果进行汇总 3.分叉合并目的:提高cpu的利用率 4.适用场景:单个任务量大的场景 5.为了防止满任务导致效率低,采取了work-stealing(窃取任务)策略,当一个核上的任务执行完成,可以去别的核上偷任务执行

package cn.tedu.pool; import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.Future; import java.util.concurrent.RecursiveTask; public class ForkJoinPoolDemo { public static void main(String[] args) throws Exception, Exception { long begin = System.currentTimeMillis(); long sum = 0; /*for(int i =0; i<1000000000L;i++){ sum+=i; }*/ //700多毫秒 ForkJoinPool pool = new ForkJoinPool(); Future<Long> result = pool.submit(new Run8(1,1000000000)); Long res = result.get(); System.out.println(res); long end = System.currentTimeMillis(); System.out.println(end-begin); } } class Run8 extends RecursiveTask<Long>{ private long start; private long end; public Run8(long start,long end){ this.start = start; this.end = end; } @Override protected Long compute() { //分叉 if(end-start>100000){ long mid = (start+end)/2; Run8 left = new Run8(start,mid); Run8 right = new Run8(mid+1,end); left.fork(); right.fork(); //合并 return left.join()+right.join(); }else{ long sum = 0; for (long i = start; i < end; i++) { sum+=i; } return sum; } } }

6.Callable-线程

1.java1.5后出现的 2.Runnable和Thread不能抛异常,Callable可以 3.Callable可以有返回值,返回值类型由泛型决定 4.Callable只能通过线程池启动

package cn.tedu.pool; 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; public class CallableDemo { public static void main(String[] args) throws Exception { ExecutorService es = Executors.newCachedThreadPool(); //Callable的返回值会封装到Future中 Future<String> result = es.submit(new CallRunner()); String str = result.get(); System.out.println(str); } } class CallRunner implements Callable<String>{ @Override public String call() throws Exception { System.out.println("线程在执行"); return "执行成功"; } }
最新回复(0)