平面设计好的网站,做采购 通常在什么网站看,网站开发所需要的的环境,网站开发报酬一、概念介绍
什么是线程#xff0c;什么是进程#xff0c;两者有什么关系#xff1f; 进程是操作系统资源分配的独立单位#xff1b;而线程是操作系统能够进行调度和分派的最小单位#xff1b;线程包含于进程之中#xff0c;是进程中的实际运作单位。
例如#xff1a…一、概念介绍
什么是线程什么是进程两者有什么关系 进程是操作系统资源分配的独立单位而线程是操作系统能够进行调度和分派的最小单位线程包含于进程之中是进程中的实际运作单位。
例如
正在运行的360安全卫士就属于一个进程 使用360卫士中的各个功能时就属于开启一个线程 1.Thread类与Runnable接口
为什么有了Thread类还要有Runnable接口两者各有什么用途 他们两个最主要的区别一个是接口一个是实现类常用接口可以避免单继承的局限性外具体区别是继承Thread类的方式可能会导致类的局部变量不能正确的被共享。因为每个线程都是一个独立的对象它们之间不能共享实例变量如果需要共享变量就必须使用静态变量或共享对象锁。而使用Runnable接口的方式多个线程可以共享同一个Runnable实例从而共享实例变量。 使用Runnable接口可以更好的体现面向对象编程的思想把任务和线程分离开来。可以把任务当作一个对象而线程可以看作是该对象任务的执行者。这样就可以更好的实现模块化设计提高代码的可重用性和可维护性。 使用Runnable接口可以更好地处理多个线程之间的交互和协作。因为实现了Runnable接口的实例可以作为参数传递给Thread类的构造函数因此线程一个Thread实例可以共享同一个Runnable实例并且多个线程可以同时执行同一个Runnable实例的不同方法从而实现多个线程之间的交互和协作。总的来说使用Runnable接口的方式更加灵活和通用可以实现更多的多线程编程场景更好的体现面向对象编程的思想提高代码的可重用性和可维护性。 但是使用Thread类的方式也有其适用的场景例如在一些简单的多线程编程场景中可以使用继承Thread类的方式来实现。
2.并发和并行的区别 (1).处理任务不同 并发(Concurrent)是一个CPU同时处理多个线程任务。宏观上是同时处理多个任务微观上其实是CPU在多个线程之间快速的交替执行。操作系统中有一个组件叫做任务调度器它将CPU的时间片分配给各个线程使用在一个时间段的线程运行时其他线程处于挂起状态这种就称之为并发。 并行(parallel)是多个CPU处理器同时处理多个线程任务。当一个CPU执行一个线程时另一个CPU可以执行另一个线程两个线程互不抢占CPU资源可以同时进行这就被称之为并行。)(2).CPU资源不同 并发过程中线程之间会去抢占CPU资源轮流便用。并行过程中线程间不会抢占CPU资源。因为是多个CPU处理器各做各的。 3.什么是线程池使用线程池有哪些优势 什么是线程池 线程池是一种线程使用模式线程池维护着多个线程等待着管理者为其分配可并发执行的任务就是可管理、维护和分配线程的“池子”。 为什么使用线程池 为了减少创建和销毁线程的次数让每个线程郜可以多次的使用 利用线程池可以根据系统情况调整线程的数量防止消耗过多内存。在实际使用中服务器在创建和销毁线程上花费的时间和系统资源都相当大使用线程池就可以优化这些消耗。 通俗的说使用线程池就是为了让线程对象可以反复的复用不需要每次执行任务时构建一个新的线程等到任务处理完后再销毁。
1使用线程池的优势 2线程池的应用场景 二、Java内置线程池的使用方法
一线程池类ThreadPoolExecutor的介绍 我们要想自定义线程池,必须先了解线程池的工作原理才能自己定义线程池 这里我们通过观察java中ThreadPoolExecutor的源码来学习线程池的原理 (源码演示在idea中查看)
1.ThreadPoolExecutor的构造方法了解这七个核心参数
public ThreadPoolExecutor(int corePoolSize, //核心线程数量int maximumPoolSize, //最大线程数long keepAliveTime, //最大空闲时间TimeUnit unit, //时间单位BlockingQueueRunnable workQueue,//任务队列ThreadFactory threadFactory, //线程工厂RejectedExecutionHandler handler //饱和处理机制) int corePoolSize核心线程数量 int maximumPoolSize最大线程数 long keepAliveTime最大空闲时间当线程空闲的时长达到该时间时会被自动回收。 TimeUnit unit设置最大空闲时间的时间单位 BlockingQueueRunnableworkQueue任务队列当线程池中所有线程都不空闲时线程池在收到任务时会在该队列中等候 ThreadFactory threadFactory线程工厂 RejectedExecutionHandler handler饱和处理机制当线程池中的线程已达到最大线程数量且都在工作并且任务队列上也已经排满等候的任务时证明当前线程池已经饱和此时再来任务将会触发该机制。 2.线程池的工作流程 我们通过下面一个场景来理解ThreadPoolExecutor中的各个参数以及线程池的工作流程: a客户(任务)去银行(线程池)办理业务但银行刚开始营业窗口服务员还未就位(相当于线程池中初始线程数量为0)于是经理(线程池管理者)就安排1号工作人员(创建1号线程执行任务)接待a客户(创建线程) 在a客户业务还没办完时b客户(任务)又来了于是经理(线程池管理者)就安排2号工作人员(创建2号线程执行任务)接待b客户(又创建了一个新的线程) 假设该银行总共就2个窗口(核心线程数量是2) 紧接着在ab客户都没有结束的情况下客户来了于是经理(线程池管理者)就安排c客户先坐到银行大厅的座位上(空位相当于是任务队列)等候并告知他: 如果1、2号工作人员空出c就可以前去办理业务 此时d客户又到了银行(工作人员都在忙大厅座位也满了)于是经理赶紧安排临时工(新创建一个线程)在大堂站着手持pad设备给d客户办理业务 假如前面的业务都没有结束的时候e客户又来了此时正式工作人员都上了临时工也上了座位也满了(临时工加正式员工的总数量就是最大线程数)于是经理只能按《超出银行最大接待能力处理办法》(饱和处理机制)拒接接待e客户 最后进来办业务的人少了大厅的临时工空闲时间也超过了1个小时(最大空闲时间)经理就会让这部分空闲的临时员工下班。(销毁线程) 但是为了保证银行正常工作(有一个alowCoreThreadTimeout变量控制是否允许销毁核心线程默认false)即使正式员工闲着也不得提前下班所以1、2号工作人员继续待着(池内保持核心线程数量) 3. 线程池的4个参数的设计:
1核心线程数(corePoolSize)
核心线程数的设计需要依据任务的处理时间和每秒产生的任务数量来确定例如:
执行一个任务需要0.1秒,系统百分之80的时间每秒都会产生100个任务,那么要想在1秒内处理完这100个任务,就需要10个线程,此时我们就可以设计核心线程数为10当然实际情况不可能这么平均,所以我们一般按照8020原则设计即可,既按照百分之80的情况设计核心线程数,剩下的百分之20可以利用最大线程数处理。
2任务队列长度(workQueue)
任务队列长度一般设计为:核心线程数/单个任务执行时间*2即可例如上面的场景中,核心线程数设计为10,单个任务执行时间为 0.1秒,则队列长度可以设计为200。
3最大线程数(maximumPoolSize)
最大线程数的设计除了需要参照核心线程数的条件外,还需要参照系统每秒产生的最大任务数决定:例如:上述环境中,如果系统每秒最大产生的任务是1000个。那么,最大线程数(最大任务数-任务队列长度)单个任务执行时间既:最大线程数(1000-200)0.180个。
4最大空闲时间(keepAliveTime)
这个参数的设计完全参考系统运行环境和硬件压力设定,没有固定的参考值,用户可以根据经验和系统产生任务的时间间隔合理设置一个值即可。
注意上面4个参数的设置只是一般的设计原则,并不是固定的,用户也可以根据实际情况灵活调整! 4.线程池类ThreadPoolExecutor的实际使用
1.自定义线程池-实现步骤 1编写任务类(MyTask)实现Runnable接口; 2编写线程类(MyWorker)用于执行任务,需要持有所有任务: 3编写线程池类(MyThreadPool)包含提交任务,执行任务的能力; 4编写测试类(MyTest)创建线程池对象,提交多个任务测试; 具体代码参考idea
小提示关于线程池的功能比较繁多这里仅仅模拟了核心功能其他功能大家可以自行考补全