四大经典案例_线程池及java代码实现
发布时间:2022-11-18 11:11:18 所属栏目:Linux 来源:
导读: 大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流
|
大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流 线程池 我们之前学过常量池!这里的线程池也大同小异! 我们通过创建很多个线程放在一块空间不进行销毁,等到需要的时候就启动线程!避免了创建销毁的时间开销! 提高开发效率! 我们之前不是说一个线程创建并不会划分很多时间吗! 但是我们的多线程编程,有时候需要使用到很多很多线程,如果要进行创建,效率就不高,而线程池或者协程(我们后面会介绍)就避免了创建销毁线程! 但我们需要用到线程时,自己从线程池中给出就好! 我们创建线程的本质还是要通过内核态(就是我们的操作系统)进行创建,然而内核态创建的时间,我们程序员无法掌控,而通过线程池,我们就可以避免了内核态的操作,直接在用户态,进行线程的调用,也就是应用程序层! 使用线程池大大提高了我们的开发效率! 我们来学习一下java中给我们提供的线程池类,然后自己实现一个线程池! ThreadPoolExecutor 线程池 这个类在java.util.concurrent并发编程包下,我们用到的很多关于并发编程的类都在! 可以看到这个线程池有4个构造方法! 在这里插入图片描述 我们了解一下参数最多的那个方法! public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 创建一个新的 ThreadPoolExecutor与给定的初始参数。 参数 corePoolSize - 即使空闲时仍保留在池中的线程数,除非设置 allowCoreThreadTimeOut maximumPoolSize - 池中允许的最大线程数 keepAliveTime - 当线程数大于内核时,这是多余的空闲线程在终止前等待新任务的最大时间。 unit - keepAliveTime参数的时间单位 workQueue - 用于在执行任务之前使用的队列。 这个队列将仅保存execute方法提交的Runnable任务。 threadFactory - 执行程序创建新线程时使用的工厂 handler - 执行被阻止时使用的处理程序,因为达到线程限制和队列容量 我们这里的线程池类比一个公司,便于我们理解该类 可以看到java给我们提供的这个线程池类让人头大! 但是不必焦虑,我们只需要知道int maximumPoolSize, 核心线程数和 maximumPoolSize 池中允许的最大线程数即可! 面试问题 思考一个问题 我们有一个程序需要多线程并发处理一些任务,使用线程池的话,需要设置多大的线程数? 这里的话,我们无法准确的给出一个数值,我们要通过性能测试的方式找个一个平衡点! 例如我们写一个服务器程序:服务器通过线程池多线程处理机用户请求!如果要确定线程池的线程数的话,就需要通过对该服务器进行性能分析,构造很多很多请求模拟真实环境,根据这里不同的线程数,来观察处理任务的速度和当个线程的cpu占用率!从而找到一个平衡点! 如果cpu暂用率过高,就无法应对一些突发情况,服务器容易挂! 我们java根据上面的ThreadPoolExecutor类进行封装提供了一个简化版本的线程池!Executors供我们使用! 我们通过Executors的使用学习,实现一个线程池! Executors java.util.concurrent.Executors 下面都是Executor类中创建线程池的一些静态方法 创建可以扩容的线程池 创建一个指定容量的线程池 创建单线程池 创建一个线程池含有任务队列 我们重点学习创建指定大小得到线程池方法! //Executors使用案例 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo3 { public static void main(String[] args) { //创建一个指定线程个数为10的线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); for (int i = 0; i < 100; i++) { int finalI = i; executorService.submit(new Runnable() { @Override public void run() { System.out.println("hello executor!"+ finalI); } }); } } } 我们通过ExecutorService类中的submit可以将多个任务注册到线程池中,然后线程池中的线程将任务并发执行,大大提升了编程效率!可以看到,啪的一下线程池linux,100个任务给10个线程一下就执行结束了! 实现线程池 我们还是分析一下线程池用什么功能,里面都有些啥! //模拟实现线程池 class ThreadPool { //描述任务 直接使用Runnable //组织任务 private BlockingQueue<Runnable> queue = new LinkedBlockingDeque<>(); //描述工作线程 static class Worker extends Thread {//继承Thread类 BlockingQueue<Runnable> queue = null; @Override public void run() { while (true){ try { //拿到任务 Runnable runnable = queue.take(); //执行任务 runnable.run(); } catch (InterruptedException e) { e.printStackTrace(); } } } //通过构造方法拿到外面的任务队列! public Worker(BlockingQueue<Runnable> queue) { this.queue = queue; } } //组织多个工作线程 //将多个工作线程放入到workers中! public List<Thread>workers = new LinkedList<>(); public ThreadPool(int n) {//指定放入线程数量 for (int i = 0; i < n; i++) {//创建多个工作线程 Worker worker = new Worker(queue); worker.start();//启动工作线程 workers.add(worker);//放入线程池 } } //创建一个方法供我们放入任务 public void submit(Runnable runnable){ try { queue.put(runnable); } catch (InterruptedException e) { e.printStackTrace(); } } } //测试代码 public class demo5 { public static void main(String[] args) { //线程池线程数量10 ThreadPool pool = new ThreadPool(10); for (int i = 0; i <100 ; i++) {//100个任务 int finalI = i; pool.submit(new Runnable() { @Override public void run() { System.out.println("hello ThreadPool "+ finalI); } }); } } } 运行效果 案例总结 MyTask类描述一个任务 Runnable + time 带有优先级的阻塞队列 扫描线程,不停从队首取出元素,检测时间是否到达,并且执行任务,使用wait解决忙等位问题! 实现schedule方法 描述一个任务Runnable 组织任务,带有优先级的阻塞队列 创建一个工作线程work类,从任务队列获取任务,执行任务 组织工作线程works数据结构存放work 实现一个submit方法将任务放入任务队列中! (编辑:我爱制作网_沈阳站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
站长推荐


浙公网安备 33038102330576号