公众号merlinsea
ThreadLocal
- ThreadLocal是每个线程的内部类,内部封装的是一个
- ThreadLocalMap<Thread,Entry>
- 可以根据不同的thread获取不同的Entry,即通过ThreadLocalMap将thread和value进行绑定!!
- 在实际微服务项目开发中我们可以使用ThreadLocal来传递一些参数给后面的方法。
/** * ThreadLocalDemo */ public class ThreadLocalDemo { /** * withInitial底层用的是 new SuppliedThreadLocal<>(supplier); */ ThreadLocal<Integer> num = ThreadLocal.withInitial(() -> 0); /** * 自增并输出num的值 */ public void inCreate() { Integer myNum = num.get(); myNum++; System.out.println(Thread.currentThread().getName() + "----------->" + myNum); num.set(myNum); } public static void main(String[] args) { ThreadLocalDemo threadLocalDemo = new ThreadLocalDemo(); for (int i = 1; i < 3; i++) { int finalI = i; new Thread(() -> { while (true) { threadLocalDemo.inCreate(); try { Thread.sleep(finalI * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } }
- ThreadPoolExecutor
- 为什么会使用线程池:许多后端应用服务会用于处理来自远端大量短小的任务请求,这些请求以某种方式到达后台服务器,可以是以网络协议的方式到达也可以是以消息队列的方式到达,但不管哪种方式,常常出现的情况是单个任务的处理时间短但请求的数量巨大,如果为每一个请求都开辟一个线程处理,那么这种频繁创建和销毁线程的操作是非常损耗系统资源和性能的。
- 线程池通过集中管理线程的生命周期,这样在一个任务到来的时候就已经有一些空闲的线程等待处理,这样可以把创建线程的开销均摊到多个任务上,同时也防止线程资源被耗尽
/** * 线程池Demo * 说明线程池的运行机制: * 参数说明: * 核心线程数10个,一直存在不会被回收 * 普通线程数最多10个,当普通线程空闲3秒就会被回收,(因为参数给定最多有20个线程,因此普通线程10个) * 工作队列可以容纳的任务数是20个 * * 首先线程池中有10个核心线程一直存在,如果来了不超过10个任务,那么核心线程会自动执行这些任务。 * 在核心线程都在执行任务时后续又来了任务,那么这些来的任务会加入到工作队列中,当核心线程空闲当时候就可以执行工作队列中的任务 * 在工作队列满了的情况下后续又来了任务,这些来的任务会开启普通线程去执行,最多开10个普通线程 * 在普通线程都用上的情况下又来了任务,那么会根据线程池配置的拒绝策略处理任务 */ public class ThreadPoolDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { //工作队列 LinkedBlockingQueue<Runnable> objects = new LinkedBlockingQueue<>(20); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,3L,TimeUnit.SECONDS,objects,new CustomPolicy()); //prestartAllCoreThreads()初始化线程池的核心线程数,否则即使有任务到达,也不会被执行(因为没有核心线程) threadPoolExecutor.prestartAllCoreThreads(); for (int i = 0; i < 50; i++) { //向线程池中提交若干任务 threadPoolExecutor.submit(()->{ try { Thread.sleep(2000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadPoolExecutor.getActiveCount()); }); } } }
另外,还可以通过Executor框架创建线程池,但建议还是使用ThreadPoolExecutor来创建线程池,因为通过Executor来创建线程池内部还是调用ThreadPoolExecutor来创建,但是Executor框架创建的线程池有发生OOM的风险(主要是因为Executor框架创建的线程池其内部要么核心线程可以开无限多个,要么工作队列无限长,这并不符合线程池管理线程生命周期以达到复用的目的,有报OOM的风险)
leetcode算法教学班双十一优惠详情
奔跑的小梁,公众号:梁霖编程工具库leetcode刷题直播教学,手把手带你刷题,双十一优惠价来啦~~