java 线程池是什么方法,java线程池(一) 简述线程池的几种使用方式
大家好,关于java 线程池是什么方法很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于java线程池(一) 简述线程池的几种使用方式的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
【Java基础】线程池的原理是什么
什么是线程池?
总归为:池化技术---》数据库连接池缓存架构缓存池线程池内存池,连接池,这种思想演变成缓存架构技术---> JDK设计思想有千丝万缕的联系
首先我们从最核心的ThreadPoolExecutor类中的方法讲起,然后再讲述它的实现原理,接着给出了它的使用示例,最后讨论了一下如何合理配置线程池的大小。
Java中的 ThreadPoolExecutor类
java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的线程池,必须先了解这个类。下面我们来看一下 ThreadPoolExecutor类的具体实现源码。
在 ThreadPoolExecutor类中提供了四个构造方法:
从上面的代码可以得知,ThreadPoolExecutor继承了 AbstractExecutorService类,并提供了四个构造器,事实上,通过观察每个构造器的源码具体实现,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。
下面解释下一下构造器中各个参数的含义:
corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者 prestartCoreThread()方法,从这 2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建 corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到 corePoolSize后,就会把到达的任务放到缓存队列当中;
maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于 corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于 corePoolSize,即当线程池中的线程数大于 corePoolSize时,如果一个线程空闲的时间达到 keepAliveTime,则会终止,直到线程池中的线程数不超过 corePoolSize。但是如果调用了 allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于 corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
unit:参数 keepAliveTime的时间单位,有 7种取值,在 TimeUnit类中有 7种静态属性:
workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:
ArrayBlockingQueue和 PriorityBlockingQueue使用较少,一般使用 LinkedBlockingQueue和 Synchronous。线程池的排队策略与 BlockingQueue有关。
threadFactory:线程工厂,主要用来创建线程;
handler:表示当拒绝处理任务时的策略,有以下四种取值:
具体参数的配置与线程池的关系将在下一节讲述。
从上面给出的 ThreadPoolExecutor类的代码可以知道,ThreadPoolExecutor继承了AbstractExecutorService,我们来看一下 AbstractExecutorService的实现:
AbstractExecutorService是一个抽象类,它实现了 ExecutorService接口。
我们接着看 ExecutorService接口的实现:
而 ExecutorService又是继承了 Executor接口,我们看一下 Executor接口的实现:
java线程池(一) 简述线程池的几种使用方式
首先说明下java线程是如何实现线程重用的
1.线程执行完一个Runnable的run()方法后,不会被杀死
2.当线程被重用时,这个线程会进入新Runnable对象的run()方法12
java线程池由Executors提供的几种静态方法创建线程池。下面通过代码片段简单介绍下线程池的几种实现方式。后续会针对每个实现方式做详细的说明
newFixedThreadPool
创建一个固定大小的线程池
添加的任务达到线程池的容量之后开始加入任务队列开始线程重用总共开启线程个数跟指定容量相同。
@Test
public void newFixedThreadPool() throws Exception{
ExecutorService executorService= Executors.newFixedThreadPool(1);
executorService= Executors.newFixedThreadPool(1, new ThreadFactoryBuilder().build());
RunThread run1= new RunThread("run 1");
executorService.execute(run1);
executorService.shutdown();
}12345678
newSingleThreadExecutor
仅支持单线程顺序处理任务
@Test
public void newSingleThreadExecutor() throws Exception{
ExecutorService executorService= Executors.newSingleThreadExecutor();
executorService= Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}123456789
newCachedThreadPool
这种情况跟第一种的方式类似,不同的是这种情况线程池容量上线是Integer.MAX_VALUE并且线程池开启缓存60s
@Test
public void newCachedThreadPool() throws Exception{
ExecutorService executorService= Executors.newCachedThreadPool();
executorService= Executors.newCachedThreadPool(new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}123456789
newWorkStealingPool
支持给定的并行级别,并且可以使用多个队列来减少争用。
@Test
public void newWorkStealingPool() throws Exception{
ExecutorService executorService= Executors.newWorkStealingPool();
executorService= Executors.newWorkStealingPool(1);
RunThread run1= new RunThread("run 1");
executorService.execute(run1);
executorService.shutdown();
}123456789
newScheduledThreadPool
看到的现象和第一种相同,也是在线程池满之前是新建线程,然后开始进入任务队列,进行线程重用
支持定时周期执行任务(还没有看完)
@Test
public void newScheduledThreadPool() throws Exception{
ExecutorService executorService= Executors.newScheduledThreadPool(1);
executorService= Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}
java线程池怎么实现的
线程池简介:
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
假设一个服务器完成一项任务所需时间为:T1创建线程时间,T2在线程中执行任务的时间,T3销毁线程时间。
如果:T1+ T3远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了
packagemine.util.thread;
importjava.util.LinkedList;
importjava.util.List;
/**
*线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息
*/
publicfinalclassThreadPool{
//线程池中默认线程的个数为5
privatestaticintworker_num=5;
//工作线程
privateWorkThread[]workThrads;
//未处理的任务
privatestaticvolatileintfinished_task=0;
//任务队列,作为一个缓冲,List线程不安全
privateList<Runnable>taskQueue=newLinkedList<Runnable>();
privatestaticThreadPoolthreadPool;
//创建具有默认线程个数的线程池
privateThreadPool(){
this(5);
}
//创建线程池,worker_num为线程池中工作线程的个数
privateThreadPool(intworker_num){
ThreadPool.worker_num=worker_num;
workThrads=newWorkThread[worker_num];
for(inti=0;i<worker_num;i++){
workThrads[i]=newWorkThread();
workThrads[i].start();//开启线程池中的线程
}
}
//单态模式,获得一个默认线程个数的线程池
publicstaticThreadPoolgetThreadPool(){
returngetThreadPool(ThreadPool.worker_num);
}
//单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数
//worker_num<=0创建默认的工作线程个数
publicstaticThreadPoolgetThreadPool(intworker_num1){
if(worker_num1<=0)
worker_num1=ThreadPool.worker_num;
if(threadPool==null)
threadPool=newThreadPool(worker_num1);
returnthreadPool;
}
//执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
publicvoidexecute(Runnabletask){
synchronized(taskQueue){
taskQueue.add(task);
taskQueue.notify();
}
}
//批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
publicvoidexecute(Runnable[]task){
synchronized(taskQueue){
for(Runnablet:task)
taskQueue.add(t);
taskQueue.notify();
}
}
//批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
publicvoidexecute(List<Runnable>task){
synchronized(taskQueue){
for(Runnablet:task)
taskQueue.add(t);
taskQueue.notify();
}
}
//销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
publicvoiddestroy(){
while(!taskQueue.isEmpty()){//如果还有任务没执行完成,就先睡会吧
try{
Thread.sleep(10);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
//工作线程停止工作,且置为null
for(inti=0;i<worker_num;i++){
workThrads[i].stopWorker();
workThrads[i]=null;
}
threadPool=null;
taskQueue.clear();//清空任务队列
}
//返回工作线程的个数
publicintgetWorkThreadNumber(){
returnworker_num;
}
//返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成
publicintgetFinishedTasknumber(){
returnfinished_task;
}
//返回任务队列的长度,即还没处理的任务个数
publicintgetWaitTasknumber(){
returntaskQueue.size();
}
//覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数
@Override
publicStringtoString(){
return"WorkThreadnumber:"+worker_num+"finishedtasknumber:"
+finished_task+"waittasknumber:"+getWaitTasknumber();
}
/**
*内部类,工作线程
*/
privateclassWorkThreadextendsThread{
//该工作线程是否有效,用于结束该工作线程
privatebooleanisRunning=true;
/*
*关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待
*/
@Override
publicvoidrun(){
Runnabler=null;
while(isRunning){//注意,若线程无效则自然结束run方法,该线程就没用了
synchronized(taskQueue){
while(isRunning&&taskQueue.isEmpty()){//队列为空
try{
taskQueue.wait(20);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
if(!taskQueue.isEmpty())
r=taskQueue.remove(0);//取出任务
}
if(r!=null){
r.run();//执行任务
}
finished_task++;
r=null;
}
}
//停止工作,让该线程自然执行完run方法,自然结束
publicvoidstopWorker(){
isRunning=false;
}
}
}
好了,本文到此结束,如果可以帮助到大家,还望关注本站哦!