1. 什么是线程池?
线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求。然而,增加可用线程数量是可能的。线程池中的每个线程都有被分配一个任务,一旦任务已经完成了,线程回到池子中并等待下一次分配任务。
2. 线程池作用
基于以下几个原因在多线程应用程序中使用线程是必须的:
1. 线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。
2. 线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。
3. 线程池根据当前在系统中运行的进程来优化线程时间片。
4. 线程池允许我们开启多个任务而不用为每个线程设置属性。
5. 线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。
6. 线程池可以用来解决处理一个特定请求最大线程数量限制问题。
3. 线程池四种创建方式
Java通过Executors(jdk1.5并发包)提供四种线程池,分别为:
- newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
- newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO, 优先级)执行。
3.1 newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:
package day4.Executors22;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NewCachedThreadTest {
public static void main(String[] args) {
// 创建可缓存线程池
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
// 执行execute 表示创建了线程。 类似 start
for (int i = 0; i < 30; i++) {
int index = i;
newCachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "----" + index);
}
});
// if (index == 9) {
// // 关闭线程池
// newCachedThreadPool.shutdown();
// }
}
}
}
总结: 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
3.2 newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:
package day4.Executors22;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NewFixedThreadPoolTest {
public static void main(String[] args) {
// newFixedThreadPool 每次最多我就只能执行三个,其他线程等待执行。
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10220000; i++) {
//int index = i;
final int index = i;
newFixedThreadPool.execute(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName() + "----" + index);
}
});
}
}
}
总结:因为线程池大小为3,每个任务输出index后sleep2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
3.3 newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
package day4.Executors22;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class NewScheduledThreadTest {
public static void main(String[] args) {
//线程池 大小
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5);
//schedule执行定时任务先吃
newScheduledThreadPool.schedule( new Runnable() {
public void run() {
System.out.println("我是三秒钟之后执行......");
}
}, 3, TimeUnit.SECONDS);
}
}
表示延迟3秒执行。
3.4 newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:
package day4.Executors22;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NewSingleThreadExecutorTest {
public static void main(String[] args) {
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
int index = i;
newSingleThreadExecutor.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + "---" + index);
}
});
}
}
}
注意:结果依次输出,相当于顺序执行各个任务。