引言
当一个业务并发量很大的时必定会用到多线程,而当运行普通的多线程程序必定会伴随着大量重复的线程创建及线程销毁,这些没有必要且重复的计算任务既会增加程序的复杂度又不符合计算机程序设计的原则导向,为了提高计算机的使用效率,前辈到老们提出了使用线程池,这样就在一定程度上避免了线程重复的创建和销毁,极大程度上提升了程序的执行效率和健壮性。
线程池简介及使用方法
什么是线程池?
- 顾名思义,线程池就是容纳线程的"池子",也就是能容纳多个多线程程序的容器,这样做优点是可以避免多线程程序在执行过程中重复关闭线程和开启线程的开销,极大程度上减少了程序的时间复杂度,而代价就是增加程序少许空间复杂度。
线程池原理
- 线程池的原理非常简单,首先要创建线程池,线程池中含有多个线程,而当系统中有多个任务片段需要执行时,当前任务片段就可与线程池中线程进行匹配,若任务成功获得线程对象就可执行任务片段了,这个过程示意图如下所示:
- 若任务执行完成后,系统将自动归还线程资源,在上述图中任务3和4没有获得线程资源,需要排队等待。
- 而线程池由集合组成,而在java中常见的集合包含ArrayList、HashSet、LinkList、HashMap,根据这些集合的特点,最适合做线程池容器的集合是LinkList,LinkList实现线程池原理示意图如下所示。
线程池案例
在jdk1.5版本之后,jdk就中就包含了线程池类,该类被统一的放在java.util.concurrent包下,若要使用线程池,则直接导包即可。与之前几篇笔记类似,小猿在本篇笔记中同样采用买票案例,以下是小猿的案例代码。
Runnable接口实现类:
public class MyRunnableImpl implements Runnable{
private static int ticket =100;
private int ticket2 =500;
private static volatile boolean sellOutFlag=false;
private String name;
public MyRunnableImpl() {
}
public MyRunnableImpl(String name) {
this.name = name;
}
@Override
public void run() {
while (!sellOutFlag) {
sellTicketStatic();
//sellTicket();
}
}
//锁对象是自己
private synchronized void sellTicket() {
if(ticket>0){
//System.out.println(this.name+"正在卖出第:"+ticket+"张票");
System.out.println(Thread.currentThread().getName()+"正在卖出第:"+ticket+"张票");
//所以打印出来会连续减三
ticket --;
//System.out.println(name+"正在卖出第:"+ticket+"张票");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
sellOutFlag = true;
}
}
//锁对象是MyRunnableImpl类
public static synchronized void sellTicketStatic(){
if(ticket>0){
//System.out.println(this.name+"正在卖出第:"+ticket+"张票");
//System.out.println(name+"正在卖出第:"+ticket+"张票");
System.out.println(Thread.currentThread().getName()+"正在卖出第:"+ticket+"张票");
ticket --;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
sellOutFlag = true;
}
}
}
测试类
public class ThreadPoolDemoTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new MyRunnableImpl("窗口一"));
executorService.submit(new MyRunnableImpl("窗口二"));
executorService.submit(new MyRunnableImpl("窗口三"));
executorService.shutdown();
}
}
测试结果
总结
上述代码中小猿将线程池的数量固定为3,而3个线程池也可以容纳3个线程的运行,所以测试结果才会有三个线程都在买票的状况,而当我们将线程池的数量固定为2时,则按照原理应当只有两个线程在卖票。至于具体测试。小猿建议各位同学在课余时间进行测试。