首先,来了解一下什么叫做线程池?线程池的作用是什么??线程池的组成部分??
1.为什么要使用线程池?
在JAVA中,对应于一个请求创建一个线程的开销是非常大的。在实际应用中,服务器在创建线程和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比处理实际的用户请求的时间和资源大得多。除了创建和销毁线程的花销大以外,活动的线程也需要消耗系统资源。如果一个JVM里创建了太多的线程,可能会使系统由于过度消耗内存或“过度切换”而导致系统资源不足。为了防止系统资源不足,需要采用一些办法来限制任何时刻处理请求的数量,尽量减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量用已有对象来进行服务,这就是“池化资源”技术产生的原因。
线程池主要是来解决线程的生命周期开销问题和资源不足的情况。通过对多个任务重复使用线程,线程创建的开销就分摊到多个任务上了,而且在用户请求时,线程已经存在,所以消除了创建线程所带来的延迟。这样就可以立即为请求服务,使应用程序响应更快。另外,适当的调整现成的数量可以防止出现资源不足的情况。
2.线程池的组成部分
一个简单的线程池至少应该包括线程池管理器、工作线程、任务队列、任务接口等部分。
线程池管理器:创建、销毁和管理线程池,将工作线程放入线程池中
工作线程:可以循环执行任务的线程,在没有任务时是进行等待的
任务队列:提供一种缓冲机制,将没有处理的任务放在任务队列中
任务接口:为所有任务提供统一的接口,以便工作线程处理。任务接口主要用来规定任务的入口。任务执行完后的收尾工作、任务的执行状态等,工作线程通过该接口调度任务的执行。
3.线程池的组成部分
当一个服务器接收到大量短小线程的请求时,使用线程池技术非常合适,可以大大减少线程的创建和销毁次数,提高服务器的工作效率。虽然说提高了工作效率,但是有得必有失,线程运行的时间及比较长了。
java通过四种Executors提供四种线程池,分别为:
1.newCachedThreadPool创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可收回,则新建新线程。
2.newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
3.newScheduledThreadPool创建一个定长线程,支持定时及周期性任务执行
4.newSingleThreadExecutor创建一个单线程,它只会用唯一的工作线程来执行任务,保证所有的任务都按照指定顺序(FIFO,LIFO)执行
(1)newCachedThreadPool
示例代码:
- package test;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- 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() {
- public void run() {
- System.out.println(index);
- }
- });
- }
- }
- }
其中,通过方法execute()可以向线程池提交任务,交由线程池去执行。
线程池为无限大,当执行第二个任务时第一个任务已经完成了,回复用执行第一个任务的线程,而不是每次新建线程。
(2)newFixedThreadPool
创建一个定长线程池,可控制线程的最大并发数,超出的线程会在队列中等待。
- package test;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
- for (int i = 0; i < 10; i++) {
- final int index = i;
- fixedThreadPool.execute(new Runnable() {
- public void run() {
- try {
- System.out.println(index);
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
- }
因为线程池的大小为3,每个任务输出index后要sleep2秒,所以每2秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime.availableProcessors()
(3)newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。
- package test;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
- public class ThreadPoolExecutorTest {
- 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);
- }
- }
- package test;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
- scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
- public void run() {
- System.out.println("delay 1 seconds, and excute every 3 seconds");
- }
- }, 1, 3, TimeUnit.SECONDS);
- }
- }
(4)newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证按照指定的顺序执行。
- package test;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
- for (int i = 0; i < 10; i++) {
- final int index = i;
- singleThreadExecutor.execute(new Runnable() {
- public void run() {
- try {
- System.out.println(index);
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
- }