天然气热水器维修
四种线程池的特点和创建线程的四种⽅式
四种线程池的特点
public static ExecutorService newCachedThreadPool(){
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
宦官当道}
public static ExecutorService newCachedThreadPool(){
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
女性赚钱60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
参数列表:
1.核⼼线程数为零
2.最⼤线程数为⽆限
3.⽆任务时,线程存活的最⼤时间为60s
4.任务队列为同步移交队列,该队列没有缓冲区,即不会有任务会在该队列中排队,每当有任务要⼊队时,队列都会将任务移交给⼀个可⽤的线程
newCachedThreadPool,是⼀种线程数量不定的线程池(没有核⼼线程),并且其最⼤线程数为Integer.MAX_VALUE,这个数是很⼤的,⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若⽆可回收,则新建线程。但是线程池中的空闲线程都有超时限制,这个超时时长是60秒,超过60秒闲置线程就会被回收。调⽤execute将重⽤以前构造的线程(如果线程可⽤)。这类线程池⽐较适合执⾏⼤量的耗时较少的任务,当整个线程池都处于闲置状态时,线程池中的线程都会超时被停⽌。
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue){
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
参数列表:
1. 核⼼线程数
2. 最⼤线程数
3. ⽆任务时,⾮核⼼线程的最⼤存活时间 为0
4. 时间单位
5. 任务队列
newFixedThreadPool 创建⼀个指定⼯作线程数量的线程池,每当提交⼀个任务就创建⼀个⼯作线程,当线程 处于空闲状态时,它们并不会被回收,除⾮线程池被关闭了,如果⼯作线程数量达到线程池初始的最⼤数,则将提交的任务存⼊到池队列(没有⼤⼩限制)中。由于newFixedThreadPool只有
核⼼线程并且这些核⼼线程不会被回收,这样它更加快速底相应外界的请求。(创建⼀个线程是⼀个很耗资源的活动,这类线程适⽤于有紧急,快速任务的场景或者时常有任务要执⾏的场景)
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize){
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize, Integer.MAX_VALUE,0, NANOSECONDS,
new DelayedWorkQueue());
}
参数列表:
1. 核⼼线程数 在创建的时候只能传⼊这个参数
2. 最⼤线程数
3. ⽆任务时,⾮核⼼线程的最⼤存活时间 为0
4. 时间单位 没有意义(因为在wScheduledThreadPool()不可以传这个参数)
5. 延迟执⾏队列
newScheduledThreadPool 创建⼀个线程池,它的核⼼线程数量是固定的,⽽⾮核⼼线程数是没有限制的,并且当⾮核⼼线程闲置时会被⽴即回收,它可安排给定延迟后运⾏命令或者定期地执⾏。这类线程池主要⽤于执⾏定时任务和具有固定周期的重复任务(如更新排名等实时活动)
public static ScheduledExecutorService newSingleThreadScheduledExecutor(){
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize, Integer.MAX_VALUE,0, NANOSECONDS,
new DelayedWorkQueue());
}
底层使⽤了newScheduledThreadPool,只有⼀个核⼼线程
newSingleThreadExecutor这类线程池内部只有⼀个核⼼线程,以⽆界队列⽅式来执⾏该线程,这使得这些任务之间不需要处理线程同步的问题,它确保所有的任务都在同⼀个线程中按顺序中执⾏,并且可以在任意给定的时间不会有多个线程是活动的。
⾃定义线程池
urrent.ThreadPoolExecutor类是线程池中最核⼼的⼀个类,因此如果要透彻地了解Java中的线程池,必须先了解这个类。下⾯我们来看⼀下ThreadPoolExecutor类的具体实现源码。
在ThreadPoolExecutor类中提供了四个构造⽅法:
public class ThreadPoolExecutor extends AbstractExecutorService {
.....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue);
索隆壁纸
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
...
}
从上⾯的代码可以得知,ThreadPoolExecutor继承了AbstractExecutorService类,并提供了四个构造器,事实上,通过观察每个构造器的源码具体实现,发现前⾯三个构造器都是调⽤的第四个构造器进⾏的初始化⼯作。
下⾯解释下⼀下构造器中各个参数的含义:
corePoolSize:核⼼池的⼤⼩,这个参数跟后⾯讲述的线程池的实现原理有⾮常⼤的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,⽽是等待有任务到来才创建线程去执⾏任务,除⾮调⽤了prestartAllCoreThreads()或者prestartCoreThread()⽅法,从这2个⽅法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者⼀个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建⼀个线程去执⾏任务,当线程池中的线程数⽬达到corePoolSize后,就会把到达的任务放到缓存队列当中;
maximumPoolSize:线程池最⼤线程数,这个参数也是⼀个⾮常重要的参数,它表⽰在线程池中最多能创建多少个线程;
keepAliveTime:表⽰线程没有任务执⾏时最多保持多久时间会终⽌。默认情况下,只有当线程池中的线程数⼤于corePoolSize
时,keepAliveTime才会起作⽤,直到线程池中的线程数不⼤于corePoolSize,即当线程池中的线程数⼤于corePoolSize时,如果⼀个线程空闲的时间达到keepAliveTime,则会终⽌,直到线程池中的线程数不超过corePoolSize。但是如果调⽤了
allowCoreThreadTimeOut(boolean)⽅法,在线程池中的线程数不⼤于corePoolSize时,keepAliveTime参数也会起作⽤,直到线程池中的线程数为0;
unit:参数keepAliveTime的时间单位
workQueue:⼀个阻塞队列,⽤来存储等待执⾏的任务,这个参数的选择也很重要,会对线程池的运⾏过程产⽣重⼤影响,⼀般来说,这⾥的阻塞队列有以下⼏种选择:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
threadFactory:线程⼯⼚,主要⽤来创建线程;
handler:表⽰当拒绝处理任务时的策略,默认有以下四种取值:
趁虚而入的体育老师2hThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前⾯的任务,然后重新尝试执⾏任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调⽤线程处理该任务
爱迪生是哪个国家的线程池执⾏的流程:
当任务提交给ThreadPoolExecutor 线程池中,先检查核⼼线程数是否已经全部使⽤,如果没有交由核⼼线程去执⾏任务,如果核⼼线程数已经全部占⽤,则将任务添加到队列⾥⾯,如果队列已经占满,⽐较当前线程池的中线程的数量是不是与超过maximumPoolSize,如果没有查过则创建线程去执⾏,
也就是说线程池最多可以接受多少任务呢?就是maximumPoolSize+队列的⼤⼩。当线程池中的线程的数量⼤于corePoolSize数量有空闲线程则执⾏回收,回收时间是keepAliveTime,单位是unit,都是初始化的时候设置的。
创建线程有⼏种⽅式?
1. 继承Thread类创建线程
2. 实现Runnable接⼝创建线程
3. 使⽤Callable和Future创建线程
使⽤Callable创建线程和Runnable接⼝⽅式创建线程⽐较相似,不同的是,Callable接⼝提供了⼀个call() ⽅法作为线程执⾏体,⽽Runnable接⼝提供的是run()⽅法,同时,call()⽅法可以有返回值,⽽且需要⽤FutureTask类来包装Callable对象。
call()⽅法特点:
1.call()⽅法可以有返回值
2.call()⽅法可以声明抛出异常。
FutureTask<Integer> task=new FutureTask<Integer>((Callable<Integer>)()->{
int i=0;
for(;i<100;i++){
System.out.println(Thread.currentThread().getName()+"===="+i);
}
//call()⽅法可以有返回值
return i;
});
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"===="+i);
if(i==20){
Thread t1=new Thread(task,"有返回值的线程");
t1.start();
美女的大屁股}
}
try{
System.out.println("⼦线程的返回值:"+());
}catch(Exception e){
e.printStackTrace();
}
4. 使⽤线程池例如⽤Executor框架
遨游汉字王国