频繁使用new Thread来创建线程的方式并不太好。因为每次new Thread新建和销毁对象性能较差,线程缺乏统一管理。好在Java提供了线程池,它能够有效的管理、调度线程,避免过多的资源消耗。优点如下:
重用存在的线程,减少对象创建、销毁的开销。
可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
提供定时执行、定期执行、单线程、并发控制等功能。
线程池原理简单的解释就是会创建多个线程并且进行管理,提交给线程的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度、管理线程池的统一调度、管理使得多线程的使用更简单高效。
线程池负责管理工作线程,包含一个等待执行的任务队列。线程池的任务队列是一个Runnable集合,工作线程负责从任务队列中取出并执行Runnable对象。
为了更好的控制多线程,jdk提供了一套Executor框架,帮助开发人员有效的进行线程控制,其本质就是一个线程池。
以上成员都在java.util.concurrent包下,是jdk并发包的核心类。其中ThreadPoolExecutor表示一个线程池。Executors类则扮演者线程池工厂的角色,通过Executors可以取得一个拥有特定功能的线程池。Executors主要提供了以下方法:
static ExecutorService newCachedThreadPool()
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available.
static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available, and uses the provided ThreadFactory to create new threads when needed.
static ExecutorService newFixedThreadPool(int nThreads)
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue.
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue, using the provided ThreadFactory to create new threads when needed.
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.
static ExecutorService newSingleThreadExecutor()
Creates an Executor that uses a single worker thread operating off an unbounded queue.
static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
Creates an Executor that uses a single worker thread operating off an unbounded queue, and uses the provided ThreadFactory to create a new thread when needed.
static ScheduledExecutorService newSingleThreadScheduledExecutor()
Creates a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically.
static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
Creates a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically.
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
/**
* Created by niehongtao on 16/7/12.
*/
public class ThreadPoolDemo {
public static class MyTask implements Runnable {
@Override
public void run() {
System.out.println(System.currentTimeMillis() + ":thread id" + Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyTask myTask = new MyTask();
ExecutorService exec = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
exec.submit(myTask);
}
}
}
/**
* Created by niehongtao on 16/7/12.
*/
public class ScheduledExecutorServiceDemo {
public static void main(String[] args) {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(System.currentTimeMillis() / 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
pool.scheduleAtFixedRate(runnable, 0, 2, TimeUnit.SECONDS);
}
}
ScheduledExecutorService有两个方法,scheduleAtFixedRate和scheduleAtFixedDelay,注意区分。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
其实核心的几个线程池,其内部都是使用了ThreadPoolExecutor来实现。即他们只是ThreadPoolExecutor类的封装。下面我们来看一下ThreadPoolExecutor:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
用给定的初始参数和默认的线程工厂及处理程序创建新的 ThreadPoolExecutor。使用 Executors 工厂方法之一比使用此通用构造方法方便得多。
参数:
corePoolSize - 池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
threadFactory - 执行程序创建新线程时使用的工厂。
handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
线程池的基本大小(corePoolSize)、最大大小(maximumPoolSize)以及存活时间等因素共同负责线程的创建与销毁。
基本大小也是线程池的目标大小,即在没有任务执行时线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。
最大大小表示可同时活动的线程数量的上限。
如果某个线程的空闲时间超过了存活时间,那么将被标记为可回收的,并且当线程池的当前大小超过基本大小时,这个线程将被终止。
ThreadPoolExecutor允许提供一个BlockingQueue来保存等待执行的任务。基本的任务排队方法有3种:有界队列, 无界队列, 同步移交(Synchronous Handoff)。
有界队列被填满后,饱和策略开始发挥作用。饱和策略可以通过调用setRejectedExecutionHandler来修改。jdk提供了几种不同的RejectedExecutionHandler实现:AbortPolicy, CallerRunsPolicy, DiscardOldestPolicy, DiscardPolicy 。
AbortPolicy:默认的饱和策略。抛出 RejectedExecutionException。调用者可以捕获这个异常,然后根据需求编写自己的处理代码。
CallerRunsPolicy: 不抛弃任务,不抛出异常,而将任务退回给调用者。
DiscardOldestPolicy:放弃最旧的未处理请求,然后重试 execute;如果执行程序已关闭,则会丢弃该任务。
DiscardPolicy:默认情况下它将放弃被拒绝的任务。
ThreadPoolExecutor是可扩展的,它提供了几个可以在子类化中改写的方法:beforeExecute、afterExcute和terminated。在这些方法中,还可以添加日志、计时、监视或统计信息收集的功能。
无论任务是从run中正常返回,还是会抛出一个异常在而返回,afterExcute都会被调用。(如果任务执行完成后带有Error,那么就不会调用afterExcute)。
如果beforeExecute抛出一个RuntimeException,那么任务将不被执行,并且afterExcute也会被调用。
在线程池完成关闭操作时调用terminated,也就是在所有任务都已经完成并且所有工作者线程也已经关闭后,terminated可以释放Executor在其生命周期里分配的各种资源,此外还可以执行发送通知,记录日志或者收集finalize统计信息等操作。
http://www.cnblogs.com/whthomas/p/java-executors.html