网站建设捌金手指花总八,办公室装修实景拍摄图,高校网站如何建设论文,给wordpress注册用户发邮件目录 线程池
为什么使用线程池
线程池的使用
工厂类Executors#xff08;工厂模式#xff09;
submit
实现一个线程池 线程池
为什么使用线程池 在前面我们都是通过new Thread() 来创建线程的#xff0c;虽然在java中对线程的创建、中断、销毁、等值等功能提供了支持…目录 线程池
为什么使用线程池
线程池的使用
工厂类Executors工厂模式
submit
实现一个线程池 线程池
为什么使用线程池 在前面我们都是通过new Thread() 来创建线程的虽然在java中对线程的创建、中断、销毁、等值等功能提供了支持一个线程的创建和销毁虽然消耗虽然小但从操作系统角度来看如果我们频繁的创建和销毁线程是需要大量的时间和资源的那么有没有什么开销更小的方法 第一种是协程它可以说是轻量级线程但是java很少用多用于go和python。 第二种是线程池java中多用线程池去解决频繁的创建和销毁线程问题。 那么为啥引入线程池就能够提升效率呢 1.直接创建/销毁线程是需要在用户态内核态配合完成的工作对于线程池只需要在用户态即可不需要内核态的配合这样开销就更小 2.等线程用完之后线程池不会销毁该线程而是让其阻塞等下次用的时候会再次利用它所以不用频繁的进行创建和销毁。 线程池最核心的设计思路复用线程平摊线程的创建与销毁的开销代价
线程池的使用 java 提供了多种方式来创建线程池主要通过Executors执行者工厂类或直接使ThreadPoolExecutor类来完成 工厂类Executors工厂模式 使用Executors工厂类 newFixedThreadPool(int nThreads)创建一个固定大小的线程池线程数量由nThreads参数确定。 newCachedThreadPool()创建一个线程数量为动态的线程池线程数量会根据任务数量动态变化当长时间没有新任务时空闲线程会被终止。 newSingleThreadExecutor()创建一个单线程的线程池它只会创建一个线程来执行任务。 newScheduledThreadPool(int corePoolSize)创建一个可以安排任务的线程池可以指定延迟执行任务或定期执行任务。 后面两个我们用的都不多主要是用前面两个 下面是使用代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService fixedThreadPool Executors.newFixedThreadPool(4);// 创建一个可缓存的线程池线程数量动态调整ExecutorService cachedThreadPool Executors.newCachedThreadPool();}
}这代码我们有个疑点我们并没有new一个对象那我们是怎么创建出来对象的呢 这个问题涉及到工厂模式这种设计模式 工厂模式是一种常用的设计模式用于封装对象的创建逻辑。它通过使用方法来创建对象new在方法内部而不是直接使用 new 关键字实例化对象。这样可以将对象的创建逻辑与使用逻辑解耦提高代码的可维护性和可扩展性。 这里就是用方法创建出对象所以涉及到了工厂模式 ThreadPoolExecutor类直接new 对于刚才讲的 Executors 本质上是 ThreadPoolExecutor 类的封装. 而对于ThreadPoolExecutor类本身我们提供了更多的可选参数, 可以进一步细化线程池行为的设定. 如下图是 ThreadPoolExecutor类的构造方法 核心线程数corePoolSize线程池中始终保持的线程数量。这是不会被销毁的。 最大线程数maximumPoolSize线程池中允许的最大线程数量。这种一般涉及到刚才的动态线程池如果任务多了则创建一些线程多了的话过了一段时间则会销毁但核心线程数不变。 空闲线程存活时间keepAliveTime当线程池中的线程数量超过核心线程数时空闲线程的存活时间。 任务队列workQueue其为阻塞队列用于存储等待执行的任务。要记住当我们创建线程池时系统也会同时自动创建一个阻塞队列去存储等待执行的任务这样效率就更高。 线程工厂threadFactory线程工厂是一个用于创建线程的工具类或接口它允许用户自定义线程的创建逻辑开发者可以控制线程的名称、优先级、异常处理等属性从而更好地管理线程资源。 拒绝策略handler当线程池已满且阻塞队列也已满时新任务的处理策略。 下面重点讲述一下拒绝策略 AbortPolicy直接抛出 RejectedExecutionException 异常。当导员给我一个任务“统计班级成员中团员个数‘’但是我现在已经课很多了我一下子就哭了出来这个就相当于直接抛异常CallerRunsPolicy由提交任务的线程直接执行任务。我直接给导员说我没空导员最后只能自己做了DiscardPolicy直接丢弃任务不抛出异常。导员一听我没空就直接说好那我也不统计了随便来了DiscardOldestPolicy丢弃队列中最老的任务然后尝试提交新任务。我听到导员的任务的时候我选择放弃我最早出现的一节课去帮导员完成任务 下面是其创建代码 ThreadPoolExecutor threadPool new ThreadPoolExecutor(2, // 核心线程数4, // 最大线程数60, // 空闲线程存活时间TimeUnit.SECONDS, // 时间单位new ArrayBlockingQueue(10), // 任务队列容量为 10Executors.defaultThreadFactory(), // 线程工厂new ThreadPoolExecutor.AbortPolicy() // 拒绝策略); 总结一下 工厂模式创建线程适合简单的线程池创建场景代码简单但灵活性有限。 构造方法创建线程适合需要灵活配置线程池属性的场景通过自定义线程池可以更好地管理线程资源提高代码的可维护性和可扩展性。 submit 通过线程池.submit继承runable的类的对象 可以提交一个任务到线程池中执行.
ExecutorService pool Executors.newFixedThreadPool(10);
pool.submit(new Runnable() {Overridepublic void run() {System.out.println(hello);}
});
实现一个线程池 这里就直接上代码了不多说重点还是使用线程池不是实现线程池。 /*** 自定义线程池执行器类* 该类通过实现一个具有固定大小的线程池和一个阻塞队列来管理线程用于异步执行任务*/
class MyThreadPoolExecutor {// 创建阻塞队列用于存放待执行的任务// 队列大小设为1000用于控制并发任务的数量避免过多任务导致资源耗尽BlockingQueueRunnable blockingQueuenew ArrayBlockingQueue(1000);/*** 构造函数初始化线程池* 创建一个线程该线程循环从阻塞队列中取任务并执行* 这个线程是线程池中的工作线程负责执行提交的任务*/public MyThreadPoolExecutor(int n) {for (int i 1; i n; i) {Thread t new Thread(() - {// 无限循环确保线程池可以持续处理任务直到程序中断或阻塞队列被清空while (true) {try {// 从阻塞队列中取出一个任务如果队列为空则线程被阻塞直到有任务放入队列Runnable task blockingQueue.take();// 执行取出的任务task.run();} catch (InterruptedException e) {// 如果线程在等待状态时被中断抛出运行时异常// 这通常会导致程序异常终止throw new RuntimeException(e);}}});// 启动线程池中的工作线程t.start();}}/*** 提交一个任务到线程池* param task 需要被执行的任务* 任务被放入阻塞队列中随后由线程池中的工作线程执行*/public void submit(Runnable task){// 将任务放入阻塞队列如果队列已满则操作会阻塞直到有空间可用blockingQueue.offer(task);}
}
class DemoTest1{public static void main(String[] args) throws InterruptedException {MyThreadPoolExecutor exnew MyThreadPoolExecutor(4);for(int i0;i100;i) {int id i;ex.submit(()-{System.out.println(Thread.currentThread().getName() 任务:id);});}}
} 多线程基础知识点到这里就告一段路了接下来我们将学习多线程进阶这部分是主要讲面试中经典题频繁的题