Java处理http协议相关初步(三)——线程池的使用分析

来源:互联网 发布:电脑版淘宝网官方网站 编辑:程序博客网 时间:2024/06/05 17:46
    接着上篇说,好歹上面也加了个线程池,用好这概念,还是有些难度的,更不要说提出这些概念的人。可是看着看着发现技术又跟我前面记录的一样,是个熟悉的过程,我们逃脱不了技术工人,我不是个合格的,因为让我从无到有的写代码,我是一点都写不出来的,O(∩_∩)O~,不过技术在手里,用在哪里就看你了,要有希望,要有激情。今天扯远啦。
    先从简单的并发的线程说起,一般实现线程都是实现Runnable接口或继承Thread类,后面又有了执行器(Executor)接口,其只有一个方法就是execute(Runnable command),其后有ExecutorService以及ScheduledExecutorService接口,对应的实现的类有ThreadPoolExecutor和ScheduledThreadExecutor,这样,Executor提供了一个简单的标准化接口,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。根据所使用的具体 Executor 类的不同,可能在新创建的线程中,现有的任务执行线程中,或者调用 execute() 的线程中执行任务,并且可能顺序或并发执行。可以从软件包 java.util.concurrent 的描述中看到这些实用的工具包对并发的支持。(下面简单的提一下,详细的应该查看标准文档)
   (1)ExecutorService(接口):具有involveAll/invokeAny,shutdown,submit,完成批量或单独的任务提交,以及任务的终止等。
   (2)ScheduledExecutorService(接口):可安排在给定的延迟运行或定期执行命令:schedule(),scheduleAtFixedRate(),scheduleWithFixDelay等。
    再说回线程池,以ThreadPoolExecutor为例,也就是前面用到得。举例说明之前其实要说的是,如果没有特别的要求,最好使用Executors来创建需要的线程池,它会很好的处理线程池中线程的维护,任务的排队等等,如newCachedThreadPool() 创建一个可根据需要创建新线程的线程池,适合于短连接,处理轻任务的情况 ,newFixedThreadPool(int nThreads) 则是创建具有可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。如果真要自己来维护,那么就要考虑几个问题就是,线程池要维持多少个常在(预先开启的,即使没有在处理任务也依然存在的)线程,最大开启多少线程(也可以无限,直到资源耗尽),当现有线程比规定的常在线程数多时,它们该怎么处理;当有大量的任务请求到时,来不及处理的任务需要排队还是抛弃等等;我们可以先看看ThreadPoolExecutor的其中一个构造函数ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler),从中看到有到核心和最大池大小,保持活动时间,排队的三种通用策略,被拒绝的任务的处理等等,我就不细说了。下面看例子

package com.test.myjava;import java.util.Queue;import java.util.concurrent.*;public class ThreadPoolTest {private static int requestNum = 0;public ThreadPoolExecutor threadPoolExecutor;public static void main(String[] args) {ThreadPoolTest tt = new ThreadPoolTest();int corePoolSize = 2;int maximumPoolSize = 5;long keepAliveTime = 30;int queueSize = 1;//5可以试一下int queueNum = 0;tt.threadPoolExecutor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit.SECONDS,new  ArrayBlockingQueue<Runnable>(queueSize),new ThreadPoolExecutor.CallerRunsPolicy() );//tt.threadPoolExecutor =(ThreadPoolExecutor) Executors.newFixedThreadPool(maximumPoolSize);for(int i=0;i<5;i++ ){System.out.println("Create Thread Num:"+i);tt.threadPoolExecutor.execute(new RequestTasks(requestNum++));queueNum = tt.getQueueSize(tt.threadPoolExecutor.getQueue());if(queueNum!=0){System.out.println("queueNum:"+queueNum);}}}private synchronized int getQueueSize(Queue queue) {return queue.size();}}// 处理请求的任务class RequestTasks implements Runnable {static int processedNum = 0;int reqNum = 0; RequestTasks(int reqNum){this.reqNum = reqNum;}public void run() {// TODO Auto-generated method stubsynchronized(this){//这里其实没用O(∩_∩)O~processedNum++;}System.out.println("ProcessedNum:" + processedNum);System.out.println("reqestNum"+reqNum);//“ 去掉注释,看看只能响应两个,有些问题”这是上篇里说到的,//自己也不懂原因,确实是不明白该怎样使用,现在清楚了while (true);}}

    如果直接运行的话,会发现当任务数达到corePoolSize规定的之后,新提交的任务就得不到执行,也是上篇说的新的请求得不到运行,可是任务队列也没有满,这是什么原因的:查看了实现的源码之后才知道,ThreadPoolExecutor的execute方法中(针对例子中使用的那个构造函数),当线程数达到corePoolSize时,新任务入队,但是只有当队伍满时或者旧有的线程运行完后才会处理队列中的任务。好了,说到这里。因此不是有特别要求还是用Executors来创建比较好。最后想说,有源码看还是很不错的,容易发现问题的所在。
原创粉丝点击