java线程池工作流程,java线程池最佳实践
前言:
虽然线程比进程轻,但是如果进一步增加创建和销毁的频率,开销还是会很高。
解决方案:线程池or协程
预先创建线程池:线程并将其放入池中,然后直接从池中使用它。你不需要在这里申请。当线程用完时,它不会返回系统,而是放回池中以备下次使用。
为什么线程放在池子里就比从系统申请释放来得更快呢?
用户写的代码运行在顶层应用上,这里的代码叫做“用户态”运行代码。一些代码需要调用API,进一步的逻辑将在内核中执行。在内核中执行的代码称为“内核态”运行的代码。创建线程就是在内核中创建一个PCB,并添加到链表中,这本身就需要内核的支持。调用Thread.start也在内核状态下运行。创建的线程在用户态下放入池中,放入池中/从池中取出的过程不涉及内核态,即用户代码即可完成。一般来说,纯用户模式的运行效率高于内核模式。
java标准库中的线程池:
ThreadPoolExecutor需要java.util.concurrent包,java中很多线程相关的组件都在concurrent包中。
线程池构造方法:
ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueueRunnable workQueue,ThreadFactory threadFactory,rejected execution handler handler)线程池参数解析:
int corePoolSize的核心线程数(正式员工数)int maximumPoolSize的最大线程数(正式员工和临时员工数)允许临时员工钓鱼的时间long keepAliveTime单位TimeUnit unit时间(秒,毫秒,美国…)BlockingQueueRunnable workQueue任务队列(线程池会提供一个提交方法让程序员在线程池中注册任务并添加到这个任务队列中)ThreadFactory threadFactory线程工厂(线程是如何创建的)RejectedExecutionHandler handler拒绝策略(任务满了怎么办?1.直接忽略最新任务。2.阻挡并等待。3.直接丢弃最旧的任务…)
一个程序需要并发/多线程来完成一些任务。如果使用线程池,这里有多少线程是合适的?
通过测试性能找到合适的值。例如,通过线程池和多线程用户请求编写一个服务器程序,可以测试这个服务器的性能。比如每秒发送500/1000/2000个请求……根据不同线程池中的线程数量,观察程序的处理速度和程序持有的CPU占用率。线程多了,整体速度会更快,但Cpu利用率也会更高。线程越少,整体速度会越慢,但CPU利用率也会降低。需要找到一个平衡点,让程序速度可以接受,CPU占用合理。不同类型程序的单个任务的计算时间和阻塞时间在CPU上的分配是不一样的,所以不是一个确定的数字。
简化版的线程池:
Executors的本质是封装ThreadPoolExecutor,并提供一些默认参数。
类线程池{ public static void main(string[]args){//创建一个固定线程数的线程池。该参数指定线程数executorservicepool=executors。NewFixedThreadpool(10);//创建一个自动扩展的线程池,线程池会根据任务量自动扩展其容量。executors . newcachedthreadpool();//创建只有一个线程的线程池,executors . newsingleheadexecutor();//创建一个带定时器功能的线程池,类似于time
r Executors.newScheduledThreadPool(10); for (int i = 0; i < 100; i++) { pool.submit(new Runnable() { @Override public void run() { System.out.println("hello threadpool"); } }); } }}线程池的组成:
1.先能够描述任务(直接使用Runnable)2.需要组织任务(直接使用BlockingQueue)3.能够描述工作线程4.还需要组织这些线程5.需要实现往线程里添加任务
class MyThreadPool{ //1.先描述一个任务,直接使用Runnable不需要产生额外类 //2.使用一个数据结构来组织若干任务 private BlockingQueue<Runnable> queue= new LinkedBlockingDeque<>(); //3.描述一个线程,工作线程的功能就是从任务队列中取任务并执行 static class Worker extends Thread{ //当前线程池中有若干个Worker线程,这些线程内部都持有了上述的任务队列 private BlockingQueue<Runnable> queue = null; public Worker(BlockingQueue<Runnable> queue){ this.queue = queue; } @Override public void run() { //就需要能够拿到上面的队列 while(true){ try { //循环的去获取任务队列中的人物 //这里如果队列为空就直接阻塞,如果队列非空就获取到里面的内容 Runnable runnable = queue.take(); //获取到后就执行 runnable.run(); } catch (InterruptedException e) { e.printStackTrace(); } } } } //4.创建一个数据结构来组织若干个线程 private List<Thread> workers = new ArrayList<>(); public MyThreadPool(int n){ //在构造方法中创建若干个线程放到上述数组中 for (int i = 0; i < n; i++) { Worker worker = new Worker(queue); worker.start(); workers.add(worker); } } //5.创建一个方法,能够允许程序员来放任务到线程池中 public void submit(Runnable runnable){ try { queue.put(runnable); } catch (InterruptedException e) { e.printStackTrace(); } }}public class 我的线程池 { public static void main(String[] args) { MyThreadPool pool = new MyThreadPool(10); for (int i = 0; i < 100; i++) { pool.submit(new Runnable() { @Override public void run() { System.out.println("hello threadpool"); } }); } }}
到此这篇关于JavaEE线程安全实现线程池方法的文章就介绍到这了,更多相关JavaEE线程安全 内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。