线程池
概念
在系统启动时,会创建一些线程,当程序需要使用线程,则从线程池中获取线程,获取到线程后进行业务操作,操作完成后再将线程归还到i线程池,等待执行下一次任务。
创建线程的三种方式
方式一:
extends Thread
public class FirstThread extends Thread{
@Override
public void run() {
while (true){
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"执行了.....");
}
}
}
启动:
FirstThread firstThread = new FirstThread();
firstThread.start();
方式二:
implements Runnable
public class SecondThread implements Runnable {
public void run() {
while (true){
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"执行了.....");
}
}
}
启动:
SecondThread secondThread = new SecondThread();
Thread t = new Thread(secondThread);
t.start();
方式三:
implements Callable
public class ThridThread implements Callable{
public Object call() throws Exception {
int i = 100;
while (i>0){
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread()+"执行了.....");
i--;
}
return null;
}
}
启动(需要借助线程池来启动):
ThridThread thridThread = new ThridThread();
Future future = Executors.newSingleThreadExecutor().submit(thridThread);
Object obj = future.get();
System.out.println(obj);
implements Ruunable和 Callable之间的区别
Runnable:
重写的是run方法,方法中没有返回值,不能向往抛出异常,可以独立启动
Callable
重写的是call方法,方法有返回值,可以向往抛出异常,需要借助线程池才能启动
使用线程池的原因
如果不使用线程池,则在多线程的运行环境中,线程会被不断的启动和关闭,成本非常高,会过度消耗系统资源从而导致系统资源的崩溃。线程池就可以很好的达到线程的重复利用,减少线程的创建和销毁成本,以达到解决上述问题的目的。
线程池的创建
核心类:ThreadPoolExecutor
打开该类可以看到一个有七个参数的构造函数
10个任务 -3 = 7-2=5-2=3
public ThreadPoolExecutor(int corePoolSize, 3
int maximumPoolSize, 5
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue, 2
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数解释:
corePoolSize: 指定核心线程池大小
maximumPoolSize:线程池中运行的最大线程数
keepAliveTime:当线程池中的线程数大于线程池的核心数量后,多出来的线程在线程池中的存活的空闲时间,销毁之前会一直等待新任务
TimeUnit:为上述时间指定时间单位
BlockingQueue:阻塞队列,用来存储还未执行的线程任务
接口的实现类:
ArrayBlockingQueue:数组阻塞队列
LinkedBlockingQueue:链表阻塞队列
DelayQueue:延迟阻塞队列
PriorityBlockingQueue:具有优先级的阻塞队列
SynchronousQueue:同步阻塞队列
ThreadFactory
创建项目的工厂类
Executors.defaultThreadFactory()
RejectedExecutionHandler:拒绝策略
当线程总数超过maximumPoolSize+BlockingQueue中的数量时的处理方式
AbortPolicy 默认,如果线程池队列满了丢掉这个任务并且抛出RejectedExecutionException异常
DiscardPolicy 如果线程池队列满了,会直接丢掉这个任务并且不会有任何异常
DiscardOldestPolicy 如果队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列
CallerRunsPolicy 如果队列满了,多出的任务会被主线程执行
自定义
常用线程池的创建
工具类Executors
Executors.newSingleThreadExecutor(); --创建只包含一个线程的线程池
Executors.newFixedThreadPool(int nThreads); --创建包含指定大小个数线程的线程池
Executors.newCachedThreadPool(); --创建一个可缓存的线程池,有多少任务会创建多少个线程
Executors.newScheduledThreadPool (int nThreads) --创建一个定长线程池,支持定时及周期性任务执行
多线程应用场景
在消息中间件中的消息如果过多,可以使用线程池来使用多个线程对消息进行消费,加速消息的消费,这样既可以用到多线程也可以是一种解决消息中间件的消息阻塞问题。