一、为什么要用线程池
1)、降低资源消耗,通过重复利用已创建的线程降低线程的创建和销毁造成的消耗。
2)、提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行。
3)、提高线程的可管理性,线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用 线程池可以进行统一的分配,调优和监控。
二、注意
1)、需要对线程池原理了如指掌。
三、线程的常见用法
1)、New Thread。
2)、Thread Pool。
四、New Thread 常见用法
new thread(new Runnable(){
@Override
public void run(){
//TODO anything you need
}
})
作为一个严谨的dev来说,new thread 一般是禁止在代码中使用的,new thread 存在许多弊端,
例如:
a)、每次new thread 都创建一个线程,性能差。
b)、线程缺乏统一管理,高并发时线程会无限制的新建,相互之间竞争资源,最终会因为占用过大资源导致死机或oom。
c)、缺乏更多扩展功能,如定时执行、定期执行、线程中断。
五、JAVA 线程池
Java 通过Executor 提供四种线程池,分别为:
newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则 创建新线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列等待。
newScheduledThreadpool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺 序(FIFO)优先级执行。
a)、newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
实例代码:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(index);
}
});
}
但是看到上面代码,大家会不会有个疑问,上面代码反复执行,不是会创建多个线程池么?
是不是应该把线程池做成单例的?
public class CachedThreadPoolProxy {
public static final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
}
下面我们来做个Test:
@Test
public void test() throwsInterruptedException {
for(inti = 1; i < 100; i++) {
final intindex =i;
ExecutorService executor= Executors.newCachedThreadPool();
executor.execute(newRunnable() {
public void run() {
System.out.println(String.format("当前线程:%d", index));
}
});
int activeCount =((ThreadPoolExecutor) executor).getActiveCount();
System.out.println(String.format("当前线程数量:%d", activeCount));
System.out.println(String.format("当前线程hashCode:%s", executor.hashCode()));
}
}
运行结果:
结论:
1、线程池会被多次创建,我们需要把线程池写成单例。
2、线程的执行是无序的。
3、会自动回收空闲线程,无空闲线程时,线程会被不断创建。
b)、newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
示例代码如下:
@Test
public void test2() throws InterruptedException {
for(inti =1; i <100; i++) {
final int index = i;
ExecutorService executor = ThreadPoolProxy.fixedThreadPool;
executor.execute(newRunnable() {
public void run() {
System.out.println(String.format("当前线程:%d", index));
}
});
int activeCount = ((ThreadPoolExecutor) executor).getActiveCount();
int blockCount = ((ThreadPoolExecutor) executor).getQueue().size();
System.out.println(String.format("当前线程数量:%d", activeCount));
System.out.println(String.format("当前线程hashCode:%s", executor.hashCode()));
System.out.println(String.format("当前队列的任务数:%s", blockCount));
}
}
结果示例:
c)、newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。
示例代码如下:
@Test
public void test3() throwsInterruptedException {
ScheduledExecutorService executor = ThreadPoolProxy.scheduledThreadPool;
executor.scheduleAtFixedRate(newRunnable() {
public void run() {
System.out.println(newDate().getTime());
System.out.println("正在执行。。。。");
}
},1,3, TimeUnit.MILLISECONDS);
}
执行上述代码时,发现程序并没有输出,心里当时充满了疑虑,几经测试,
猜想是因为主线程终止了,schedual 也会停止运行。
于是便用下面代码做测试
@Test
public void test3() throws InterruptedException {
ScheduledExecutorService executor = ThreadPoolProxy.scheduledThreadPool;
executor.scheduleAtFixedRate(newRunnable() {
public void run() {
System.out.println(newDate().getTime());
System.out.println("正在执行...");
}
},1,3, TimeUnit.MILLISECONDS);
Thread.sleep(100000);
运行结果:
结论:猜想证实成功,scheduleAtFixedRate 方法会在delay 时间后,按周期循环执行。
d)、newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执 行。
@Test
public void test4() throws InterruptedException {
ExecutorService executor = ThreadPoolProxy.singleThreadExecutor;
for(inti =0; i <10000; i++) {
final int index = i;
executor.execute(newRunnable() {
public void run() {
System.out.println(index);
}
});
}
}
可以看出结果依次输出。
本人学识有限,以上纯属个人鄙见,如有问题,请直接指出,本人当及时改正,感谢!
PS: 下期将介绍
1、线程池的原理及核心概念。
2、Spring 中线程池的应用。