栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java——线程池(一)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java——线程池(一)

1、为什么要使用线程池?
例如:当前我们有一个任务,任务内容为输出当前线程的名称,然后我们创建一个该任务,创建一个线程,将该任务交给该线程,然后启动线程。

public class Task implements Runnable{
    @Override
    public void run() {
        //输出当前线程的名称
        System.out.println(Thread.currentThread().getName());
    }
}
public class ThreadPool001 {
    public static void main(String[] args) {
        //创建任务
        Runnable task = new Task();
        //创建线程
        Thread thread = new Thread(task);
        //启动线程
        thread.start();
    }
}
输出结果:
"C:Program FilesJavajdk1.8.0binjava.exe"
Thread-0

我们的一个线程它只能执行一个任务,我们不能创建多个任务,并将它们都放在同一个线程连续执行,我们只能重新再创建其他线程,启动并执行。线程在执行完任务之后就会销毁,如果再有任务要执行的话,需要重新创建线程。导致问题就是**线程不能复用,重复创建和销毁线程会耗时、耗资源,**此时我们要考虑线程如果可以复用就好了,其好处就是省时省资源,我们可以看看线程池是如何执行任务的。

public class ThreadPool001 {
    public static void main(String[] args) {
        //创建任务
        Runnable task1 = new Task();
        Runnable task2 = new Task();
        Runnable task3 = new Task();
        //创建只有一个线程的线程池
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //提交任务
        threadPool.execute(task1);
        threadPool.execute(task2);
        threadPool.execute(task3);
        //线程池会自动分配线程去执行提交的任务,最后需要调用shutdown方法关闭线程池
        threadPool.shutdown();
    }
}

我们创建一个只有一个线程的线程池threadPool,将创建的三个任务提交到该线程池中,线程池会自动分配线程去执行提交的任务,最后需要调用shutdown方法关闭线程池。当线程池关闭以后,无法再提交任务。

输出结果:
"C:Program FilesJavajdk1.8.0binjava.exe" 
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1

通过结果我们可以看到一个线程执行了三个任务,此时则可以正面线程得到了复用。相比于线程,线程池的好处有很多,此处列举三个:

  • 降低资源消耗:通过重复利用已经创建的线程降低线程创建和销毁造成的消耗;
  • 提高响应速度:当有任务时,可以不用等待线程创建就能立即执行;
  • 提高线程的可管理性:线程池可以进行统一的分配、调优和监控。

线程在我们的系统中属于稀缺资源,无限制重复的创建不仅消耗系统资源,还会降低系统的稳定性。

2、什么是线程池?

线程池(Thread Pool)一种基于池化思想管理线程的工具。线程池事先将线程创建好,当有任务需要执行时,将任务提交给线程池,线程池分配线程去执行,线程池中的线程还可以复用,执行完一个线程可以接着执行其他任务。当所有的任务都执行完后,我们可以选择关闭线程池,也可以选择等待接收任务。

ThreadPool的UML 类图:

3、为什么推荐使用原生方式创建线程池?

创建线程池的方式有8种,但是万变不离其宗,就是原生创建线程池的方式,这种方式也是阿里极力推荐的一种,其手册中说明线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式去创建,其他的方式有资源消耗的风险。

从上面的类图中我们可以看到可以实例化的只有ThreadPoolExecutor和ScheduleThreadPoolExecutor这两个,其中ThreadPoolExecutor是线程池的核心类,该核心类一共有四个构造方法,不过都大同小异,我们可以从最后一个构造方法参数最多的开始了解。

第一种:参数最多

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

参数含义:
corePoolSize: 线程池核心线程数量 int类型

maximumPoolSize:线程池允许线程的最大数量 int类型

keepAliveTime: 线程池中线程所允许的空闲时间。long类型

unit: 线程池维护线程所允许的空闲时间的单位

 MICROSEConDS    微秒   一百万分之一秒(就是毫秒/1000)
 MILLISEConDS    毫秒   千分之一秒    
 NANOSEConDS   毫微秒  十亿分之一秒(就是微秒/1000)
 SEConDS          秒
 MINUTES     分钟
 HOURS      小时
 DAYS      天

workQueue: 线程池所使用的缓冲队列

handler: 线程池对拒绝任务的处理策略

ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务。

threadFactory:线程工厂,主要用来创建线程:默认值 DefaultThreadFactory


例如:
corePoolSize:10
maximumPoolSize:25
keepAliveTime:10
unit:TimeUnit.SECONDS

空闲线程存活时间是10秒,10秒内没有工作就会被销毁;如果空闲时间是0秒的话,空闲线程不会被销毁。线程池中有10个核心线程,如果线程池不关闭,这10个核心线程就不会被销毁,线程池中最多允许25个线程,除去核心线程外的线程为非核心线程,非核心线程不执行任务就会被清理销毁,在被清理销毁前能存活多久取决于keepAliveTime和unit。

workQueue任务队列:线程池的任务都存放在这个容器中,线程池中的线程也是从这个容器中获取任务。一般用的任务队列是基于链表的linkedBlocklingQueue链式阻塞队列和基于数组的ArrayBlocklingQueue数组阻塞队列。

threadFactory线程工厂:这是一个接口,可通过实现它内部的newThread方法,自定义线程的相关设置,如可以指定线程名称,利于在后期日志中查看线程的执行情况;还可以指定线程是否可以为后台线程等。

handler线程拒绝策略:同时满足以下四种情况,提交给线程池的任务会被拒绝。

  • 线程池中的线程已满
  • 无法再继续扩容
  • 没有空闲线程,所有线程都在执行任务
  • 任务队列已满,无法存入新任务

代码示例:

任务类:输出当前线程的名称
public class Task implements Runnable{
    @Override
    public void run() {
        //输出当前线程的名称
        System.out.println(Thread.currentThread().getName());
    }
}
线程工厂类:
public class CustomThreadFactory implements ThreadFactory {
    //定义一个计数器,给线程编号,初始编号为1,避免发生线程安全问题
    private final AtomicInteger i = new AtomicInteger(1);
    @Override
    public Thread newThread(Runnable r) {
        //创建线程,并指定任务
        Thread thread = new Thread(r);
        //设置线程名称
        thread.setName("线程:"+i.getAndIncrement()+"号");
        //返回线程
        return thread;
    }
}
public class ThreadPool001 {
    public static void main(String[] args) {
        //创建任务
        Runnable task1 = new Task();
        Runnable task2 = new Task();
        Runnable task3 = new Task();
        //创建线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(10, 25, 10,
                TimeUnit.SECONDS,
                new linkedBlockingQueue<>(),
                new CustomThreadFactory(),  //刚刚创建的线程工厂
                new AbortPolicy());//默认拒绝策略
        //提交任务
        threadPool.execute(task1);
        threadPool.execute(task2);
        threadPool.execute(task3);
        //关闭线程池
        threadPool.shutdown();
    }
}
输出结果:
"C:Program FilesJavajdk1.8.0binjava.exe" 
线程:1号
线程:3号
线程:2号
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/324718.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号