什么是线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
线程池的类型
1.CachedThreadPool
适合使用在任务量 大但耗时少的任务。
2.FixedThreadPool
适合使用在任务量比 较固定但耗时长的任务。
3.ScheduledThreadPool
适合使用在执行 定时任务和具体固定周期的重复任务。
4.SingleThreadPool
适合使用在多个任务 顺序执行的场景。
5.newWorkStealingPool
适合使用在很耗 时的任务中。
线程池的好处
1、线程池的重用
线程的创建和销毁的开销是巨大的,而通过线程池的重用大大减少了这些不必要的开销,当然既然少了这么多消费内存的开销,其线程执行速度也是突飞猛进的提升。
2、控制线程池的并发数
控制线程池的并发数可以有效的避免大量的线程池争夺CPU资源而造成堵塞。
3、线程池可以对线程进行管理
线程池可以提供定时、定期、单线程、并发数控制等功能。比如通过ScheduledThreadPool线程池来执行S秒后,每隔N秒执行一次的任务。
线程池的示例
拿NewFixedThreadPool线程池举例。newFixedThreadPool的特点是他的核心线程数和最大线程数是一致的,并且是一个固定线程数的线程池。线程池的大小一旦达到最大值后,再有新的任务提交时则放入无界阻塞队列中,等到有线程空闲时,再从队列中取出任务继续执行。
1.Client启动类
import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @BelongsProject: demo * @BelongsPackage: com.wzl * @Author: Wuzilong * @Description: 线程池-多线程 * @CreateTime: 2022-12-30 08:55 * @Version: 1.0 */ public class Client { public static void main(String[] args) { ExecutorService executorService= Executors.newFixedThreadPool(80); //构造CountDownLatch传入数量为10000,初始化的计数器大小为1000,与学生数量对应。 List<String> number=new ArrayList<>(); for (int i = 0; i < 10000; i++) { number.add( "少了" +i +"袋牛奶"); } final CountDownLatch latch = new CountDownLatch(number.size()); //计算1000个学生的学习数据 for (int i = 0; i <number.size() ; i++) { //线程提交任务 executorService.submit(new DrinkMilk(i,latch,number)); } try{ //使调用该方法的主线程处于等待状态,当倒数到0时主线程才执行。 latch.await(); } catch (InterruptedException e) { throw new RuntimeException("XXX喝牛奶多线程处理异常",e); } //关闭线程池 executorService.shutdown(); } }
newFixedThreadPool(80):80指的是线程池的固定大小,根据电脑的配置情况来启动对应的线程数
new DrinkMilk(i,latch,number):将具体业务需要用到的对象或者值通过实例化对象以构造函数的形式传到具体业务类中
CountDownLatch(number.size()):等子线程都执行完毕之后,主线程才继续执行。传入的参数要和执行的线程是一致的
2.具体业务类:实现Runnable接口,并实现了run方法
import java.util.List; import java.util.concurrent.CountDownLatch; /** * @BelongsProject: demo * @BelongsPackage: com.wzl * @Author: Wuzilong * @Description: 具体业务类 * @CreateTime: 2022-12-30 08:55 * @Version: 1.0 */ public class DrinkMilk implements Runnable { int drinkMilkNumber; CountDownLatch latch; List<String> number; public DrinkMilk(int drinkMilkNumber, CountDownLatch latch, List<String> number) { this.drinkMilkNumber=drinkMilkNumber; this.latch=latch; this.number=number; } @Override public void run() { this.business(); latch.countDown(); } private void business(){ System.out.println("XXX喝了"+drinkMilkNumber+"袋牛奶!"+Thread.currentThread().getName()); } }
3.执行结果