Java线程池
http://blog.csdn.net/evankaka/article/details/51489322
在线程池中执行任务比为每个任务分配一个线程优势更多,通过重用现有的线程而不是创建新线程,可以在处理多个请求时分摊线程创建和销毁产生的巨大的开销。当请求到达时,通常工作线程已经存在,提高了响应性;通过配置线程池的大小,可以创建足够多的线程使CPU达到忙碌状态,还可以防止线程太多耗尽计算机的资源。
一、Executors的API介绍
Java类库提供了许多静态方法来创建一个线程池:a、newFixedThreadPool 创建一个固定长度的线程池,当到达线程最大数量时,线程池的规模将不再变化。 b、newCachedThreadPool 创建一个可缓存的线程池,如果当前线程池的规模超出了处理需求,将回收空的线程;当需求增加时,会增加线程数量;线程池规模无限制。 c、newSingleThreadPoolExecutor 创建一个单线程的Executor,确保任务对了,串行执行 d、newScheduledThreadPool 创建一个固定长度的线程池,而且以延迟或者定时的方式来执行,类似Timer; 小结一下:在线程池中执行任务比为每个任务分配一个线程优势更多,通过重用现有的线程而不是创建新线程,可以在处理多个请求时分摊线程创建和销毁产生的巨大的开销。当请求到达时,通常工作线程已经存在,提高了响应性;通过配置线程池的大小,可以创建足够多的线程使CPU达到忙碌状态,还可以防止线程太多耗尽计算机的资源。
创建线程池基本方法:(1)定义线程类[java] view plain copyclass Handler implements Runnable{ } (2)建立ExecutorService线程池[java] view plain copyExecutorService executorService = Executors.newCachedThreadPool(); 或者 [java] view plain copyint cpuNums = Runtime.getRuntime().availableProcessors(); //获取当前系统的CPU 数目 ExecutorService executorService =Executors.newFixedThreadPool(cpuNums * POOL_SIZE); //ExecutorService通常根据系统资源情况灵活定义线程池大小 (3)调用线程池操作循环操作,成为daemon,把新实例放入Executor池中 [java] view plain copywhile(true){ executorService.execute(new Handler(socket)); // class Handler implements Runnable{ 或者 executorService.execute(createTask(i)); //private static Runnable createTask(final int taskID) } execute(Runnable对象)方法其实就是对Runnable对象调用start()方法(当然还有一些其他后台动作,比如队列,优先级,IDLE timeout,active激活等)
1.CachedThreadPoolCachedThreadPool首先会按照需要创建足够多的线程来执行任务(Task)。随着程序执行的过程,有的线程执行完了任务,可以被重新循环使用时,才不再创建新的线程来执行任务。我们采用《Thinking In Java》中的例子来分析。客户端线程和线程池之间会有一个任务队列。当程序要关闭时,你需要注意两件事情:入队的这些任务的情况怎么样了以及正在运行的这个任务执行得如 何了。令人惊讶的是很多开发人员并没能正确地或者有意识地去关闭线程池。正确的方法有两种:一个是让所有的入队任务都执行完毕(shutdown()), 再就是舍弃这些任务(shutdownNow())——这完全取决于你。比如说如果我们提交了N多任务并且希望等它们都执行完后才返回的话,那么就使用 shutdown():
FixedThreadPool模式会使用一个优先固定数目的线程来处理若干数目的任务。规定数目的线程处理所有任务,一旦有线程处理完了任务就会被用来处理新的任务(如果有的话)。这种模式与上面的CachedThreadPool是不同的,CachedThreadPool模式下处理一定数量的任务的线程数目是不确定的。而FixedThreadPool模式下最多 的线程数目是一定的。
3、newSingleThreadExecutor其实这个就是创建只能运行一条线程的线程池。它能保证线程的先后顺序执行,并且能保证一条线程执行完成后才开启另一条新的线程
4、newScheduledThreadPool这是一个计划线程池类,它能设置线程执行的先后间隔及执行时间等,功能比上面的三个强大了一些。
ScheduledThreadPoolExecutor的定时方法主要有以下四种: 下面将主要来具体讲讲scheduleAtFixedRate和scheduleWithFixedDelayscheduleAtFixedRate 按指定频率周期执行某个任务 public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); command:执行线程 initialDelay:初始化延时 period:两次开始执行最小间隔时间 unit:计时单位 scheduleWithFixedDelay 周期定时执行某个任务/按指定频率间隔执行某个任务(注意) public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); command:执行线程 initialDelay:初始化延时 period:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间) unit:计时单位
1.按指定频率周期执行某个任务 下面实现每隔2秒执行一次,注意,如果上次的线程还没有执行完成,那么会阻塞下一个线程的执行。即使线程池设置得足够大。
executor.scheduleAtFixedRate(new MyHandle(),0,2000, TimeUnit.MILLISECONDS); }
间隔指的是连续两次任务开始执行的间隔。对于scheduleAtFixedRate方法,当执行任务的时间大于我们指定的间隔时间时,它并不会在指定间隔时开辟一个新的线程并发执行这个任务。而是等待该线程执行完毕。
2、按指定频率间隔执行某个任务
}
3.周期定时执行某个任务 周期性的执行一个任务,可以使用下面方法设定每天在固定时间执行一次任务。
}
4、shutdownNow()不管当前有没有线程在执行,马上关闭线程池!这个方法要小心使用,要不可能会引起系统数据异常!
总结: ThreadPoolExecutor中,包含了一个任务缓存队列和若干个执行线程,任务缓存队列是一个大小固定的缓冲区队列,用来缓存待执行的任务,执行线程用来处理待执行的任务。每个待执行的任务,都必须实现Runnable接口,执行线程调用其run()方法,完成相应任务。 ThreadPoolExecutor对象初始化时,不创建任何执行线程,当有新任务进来时,才会创建执行线程。
构造ThreadPoolExecutor对象时,需要配置该对象的核心线程池大小和最大线程池大小: 当目前执行线程的总数小于核心线程大小时,所有新加入的任务,都在新线程中处理 当目前执行线程的总数大于或等于核心线程时,所有新加入的任务,都放入任务缓存队列中 当目前执行线程的总数大于或等于核心线程,并且缓存队列已满,同时此时线程总数小于线程池的最大大小,那么创建新线程,加入线程池中,协助处理新的任务。 当所有线程都在执行,线程池大小已经达到上限,并且缓存队列已满时,就rejectHandler拒绝新的任务
RejectedExecutionHandler handler)//拒绝策略
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 博客链接:http://www.ideabuffer.cn/2017/04/04/深入理解Java线程池:Thre...
- 更多 Java 并发编程方面的文章,请参见文集《Java 并发编程》 线程组 Thread Group 线程的集合...
- ruby-china更改域名后的更新。由于国内网络原因,mac自带的ruby源https://rubygems.o...