new Thread的弊端:
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
}).start();
1.线程的创建和释放,需要占用不小的内存和资源,每次new Thread新建对象性能差。
2.线程缺乏统一管理,相互之间存在资源竞争,可能会占用过多资源而导致死机或者OOM
3.功能单一,缺乏定时执行,定期执行,线程中断等。
ExecutorService的优点:
1,重用存在的线程,减少对象创建、消亡的开销,性能较好。
2.可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
3.提供定时执行,定期执行,单线程,并发数控制等功能。
Java线程池
ExecutorService是Java提供的线程池,也就是,每次需要使用线程时,可以通过Executor获取线程。它可以有效控制最大并发线程数,提高系统资源使用率,同时避免过多资源竞争阻塞,同时提供定时执行、定期执行、单线程、并发数控制等功能,也不用使用TimeTask了。
Java通过Executors提供四种线程池:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor创建一个单线程化线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。
ExectorService的创建方式
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
通过看源码得出:所有的线程池都是通过上面这个方法来创建的。
corePoolSize:核心线程数,一旦创建将不再释放。如果创建的线程数还没有达到指定的核心线程数,将会继续创建新的核心线程,直到达到最大核心线程数后,核心线程将不再增加;如果没有空闲的核心线程,同时又未达到最大线程数,则将继续创建非核心线程;如果核心线程数等于最大线程数,则当核心线程都处于激活状态时,任务将被挂起,等待空闲核心线程来执行。
maximumPoolSize:最大线程数,允许创建的最大线程数量。如果最大线程数量等于核心线程数,则无法创建非核心线程;如果非核心线程处于空闲时,超过设置的空闲时间,则将被回收,释放占用的资源。
keepAliveTime:当线程空闲时,所允许保存的最大时间,超过这个时间,线程将被释放销毁,只针对非核心线程。
util:时间单位,TimeUnit.SECONDS等
workQueue:任务队列,存储暂时无法执行的任务,等待空闲线程来执行任务。
threadFactory:线程工程,用于创建线程
handler:当线程边界和队列容量已经达到最大时,用于处理阻塞时的程序。
下面分别说下各个线程池:
1.newCacheThreadPool 可缓存线程池
ExecutorService cachePool = Executors.newCachedThreadPool();
具体创建源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
可以看到,创建的都是非核心线程,而且最大线程数为Integer的最大值,空闲线程的存活时间是1分钟,如果有大量耗时任务,则不适合该创建方式,它只适用于生命周期短的任务。
测试代码:
public class ExectorServiceTest {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" "+index);
}
});
}
cachedThreadPool .shutdown();
}
}
运行结果: 执行第二个任务时第一个任务已经完成,会复用第一个任务的线程,而不是每次新建线程
2.newFixedThreadPool 固定线程数线程池
Executors.newFixedThreadPool(3);
具体源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
也就是创建固定数量的可复用线程数(核心线程不会被释放所以是可复用的),来执行任务。当线程数达到最大核心线程数,则加入队列等待有空闲线程是再执行。
public class ExectorServiceTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 6; i++) {
final Integer index = i;
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index+"->"+index.hashCode());
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
fixedThreadPool.shutdown();
}
}
线程池大小为3,每个任务输出index后sleep1秒,所以每隔一秒打印3个数字,打印截图:
3.newScheduledThreadPool 定长线程池 支持定时和周期性任务
ExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
具体源码:
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
可用于替代handler.postDelay和Timer定时器等延时和周期性任务。
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
schedule方法:在dalay unit(即几秒后或者几分钟等)后执行
scheduleAtFixedRate方法:initialDelay + x * period 首先暂停initialDelay然后每次间隔period
sheduleWithFixedDelay方法:(initialDelay + period)*n每次都间隔(initialDelay + period)
public class ExectorServiceTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
},3, TimeUnit.SECONDS);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
}
}
打印结果:
4.newSingleThreadExecutor 单线程池
ExecutorService singlePool = Executors.newSingleThreadExecutor();
具体源码:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
顾名思义就是创建一个核心线程,保证任务按FIFO顺序(先进先出)一个个执行。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
现在大多数GUI程序都是单线程。适用于批量删除,批量安装等不适合并发但是可能IO阻塞的操作。