线程池使用及优势
线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
主要特点
线程复用;控制最大并发数;管理线程。
- 第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 第二,提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
- 第三,提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
线程池如何使用?
架构说明
Java中的线程池是通过Executor框架实现的,该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor这几个类。
线程池的底层就是ThreadPoolExecutor
线程池3个常用方式
newFixedThreadPool
package com.threadTest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 线程池
* 第四种获得/使用java多线程的方式, 前三种分别是 继承Thread类,实现Runnable接口,实现callable接口(有返回值有异常)
*
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
//一池5个处理线程
ExecutorService threadPool = Executors.newFixedThreadPool(5);
//模拟10个用户来办理业务,每个用户就是一个来自外部的请求线程
try {
for (int i = 1; i <= 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName()+"\t 办理业务");
});
}
} catch (Exception e) {
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
newSingleThreadExecutor
package com.threadTest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 线程池
* 第四种获得/使用java多线程的方式, 前三种分别是 继承Thread类,实现Runnable接口,实现callable接口(有返回值有异常)
*
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
//一池1个处理线程
ExecutorService threadPool = Executors.newSingleThreadExecutor();
//模拟10个用户来办理业务,每个用户就是一个来自外部的请求线程
try {
for (int i = 1; i <= 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName()+"\t 办理业务");
});
}
} catch (Exception e) {
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
newCachedThreadPool
package com.threadTest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 线程池
* 第四种获得/使用java多线程的方式, 前三种分别是 继承Thread类,实现Runnable接口,实现callable接口(有返回值有异常)
*
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
//一池N个处理线程
ExecutorService threadPool = Executors.newCachedThreadPool();
//模拟10个用户来办理业务,每个用户就是一个来自外部的请求线程
try {
for (int i = 1; i <= 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName()+"\t 办理业务");
});
}
} catch (Exception e) {
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
但是如果每次停0.2秒呢?
package com.threadTest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 线程池
* 第四种获得/使用java多线程的方式, 前三种分别是 继承Thread类,实现Runnable接口,实现callable接口(有返回值有异常)
*
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
//一池N个处理线程
ExecutorService threadPool = Executors.newCachedThreadPool();
//模拟10个用户来办理业务,每个用户就是一个来自外部的请求线程
try {
for (int i = 1; i <= 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName()+"\t 办理业务");
});
//暂停200毫秒
try {TimeUnit.MILLISECONDS.sleep(200);}catch(InterruptedException e) {e.printStackTrace();}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
说明应付得过来就不需要那么多线程,这个机制是灵活处理。
底层是什么?
底层都是ThreadPoolExecutor
newFixedThreadPool
- 1.创建一个定长线程池,可以控制线程最大并发数,超出的线程会在队列中等待
- 2.newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值时相等的,它使用的LinkedBlockingQueue;
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor
- 1.创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。
- 2.newSingleThreadExecutor将corePoolSize和maximumPoolSize都设置为1,它使用的LinkedBlockingQueue;
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newCachedThreadPool
- 1.创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- 2.newCachedThreadPool将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使用的SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程。