本篇来看下java线程池相关技术的实现和使用方式。java
一开始咱们想要实现多线程最一般的作法是:编程
new Thread(new Runnable() { public void run() { System.out.println("raw thread"); } }).start();
这种方式,这种实现方式也没有什么很差,只是若是线程一多的话很差对全部的线程进行统一管理。而后java有了线程池技术,咱们能够经过线程池技术来替换实现上面的方式。多线程
ExecutorService executorPool = Executors.newCachedThreadPool(); Future<String> future = executorPool.submit(new Callable<String>() { public String call() throws Exception { return "future finish"; } }); try { System.out.println(future.get()); } catch (Exception e) { e.printStackTrace(); }
Executors有以下几种方式建立线程:ide
newCachedThreadPool函数
newFixedThreadPool线程
newScheduledThreadPoolcode
上面三种方式最终都是调用ThreadPoolExecutor的构造函数进行线程池的建立,只是传入的参数不同,而实现不一样的线程池对象。对象
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize:建立线程池时建立多少个线程。队列
maximumPoolSize:这个线程池中对多能有多少个线程。get
keepAliveTime:当线程数量超过corePoolSize时,多余的空闲线程最大的存活时间。也就是说多余的线程在keepAliveTime时间仍是没有处理任何的任务将会被终止。
unit:时间单位
workQueue:这个线程池中线程处理任务的的任务队列。
threadFactory:建立新线程的线程工厂。
handler:当线程数量达到maximumPoolSize,对新加入的任务的处理策略。通常不多使用这个参数基本都采用默认的handler。
上面的例子中咱们向线程池中提交了一个Callable,并接受一个返回值Future。Callable可能会是一个很是耗时的操做可是使用方有不想阻塞等待其返回再继续执行,这时Callable执行完后会将结果放到Future中,使用方能够在须要的时候去判断是否Callable已经执行完成,若是完成就能够经过Future拿到其返回值。
任务定时调度线程的使用:
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println("schedule task with fixed rate:" + System.currentTimeMillis()); } }, 2000, 1000, TimeUnit.MILLISECONDS); scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { public void run() { System.out.println("schedule task with fixed delay:" + System.currentTimeMillis()); int count = Integer.MAX_VALUE; while (count-- > 0){ } System.out.println("time:" + System.currentTimeMillis()); } }, 2000, 1000, TimeUnit.MILLISECONDS);
ScheduledExecutorService有两种定时调度的方式:
scheduleAtFixedRate:以固定速率进行调度,意思是任何两个被调度的任务之间的时间间隔是固定的。第二个任务的调度时间(开始执行时间)= 第一个任务的调度时间 + 间隔时间
scheduleWithFixedDelay:第二个任务的调度时间 = 第一个任务的调度时间 + 第一个任务的执行时间 + 间隔时间
上面介绍了ScheduledExecutorService来作定时任务,在编程的过程当中还可使用Timer来作定时任务,代码以下:
timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { doSomething(); } catch (Exception e) { System.out.println("timer excute exception", e); } } }, 1000 * 3, 1000);
其第一参数是一个TimerTask,第二第三个参数scheduledExecutorService.scheduleAtFixedRate
这个调用的第二三个参数一致。
我以为最好的参考仍是阅读相关源码去理解Executor的使用方式,这样本身才能理解的比较深刻同时作到活学活用。线程池的的核心实现ThreadPoolExecutor,想了解更多仍是本身去look look源码吧。