java多线程(线程池)

目录

池化技术

线程池

概述

意义

优势

线程池参数说明

WorkQueue工作队列

1.SynchronousQueue

2.LinkedBlockingQueue

3.ArrayBlockingQueue

4.DelayQueue

拒绝策略

使用风险

创建方式

newCacheTreadPool(可缓存)

newFixedThread(固定大小)

newScheduleThreadPool(无限大小)

newSingleExecutor(单线程)

 ThreadPoolExecutor

 处理流程

线程池状态

线程配置


池化技术

        池化技术指的是提前准备一些资源,在需要时可以重复使用这些预先准备的资源。池化技术的优点主要有两个:提前准备和重复利用;

        常见的池化技术的应用有:线程池、内存池、数据库连接池、HttpClient 连接池

好处

        1.复用线程,降低资源消耗

        2.提高响应速度

        3.管控线程数和任务数

线程池

概述

线程池是一种可以复用线程的技术;

意义

        线程是稀缺资源,它创建与销毁是相对偏重且耗资源的操作;线程池就是一个线程缓存,负责对线程进行统一分配、调优与监控。

优势

        1、提高效率,创建好一定数量的线程放在池中等待,比需要时重新创建要快的多

        2、减少创建和销毁的次数

        3、提高响应速度

线程池参数说明

/**
     * 用给定的初始参数创建一个新的ThreadPoolExecutor。
     */
    public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
                              int maximumPoolSize,//线程池的最大线程数
                              long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
                              ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
                              RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
                               ) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

WorkQueue工作队列

workQueque决定了缓存任务的排队策略,对于不同的业务场景,我们可以选择不同的工作队列。

1.SynchronousQueue

        没有容量,直接提交队列,是无缓存等待队列,当任务提交进来,它总是马上将任务提交给线程去执行,如果线程已经达到最大,则执行拒绝策略

2.LinkedBlockingQueue

        默认情况下,LinkedBlockingQueue是个无界的任务队列,默认值是Integer.MAX_VALUE,当然我们也可以指定队列的大小。从构造LinkedBlockingQueue源码中可以看出它的大小指定方式

   //默认构造函数,大小为Integer最大
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

   //也可以指定大小
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }
3.ArrayBlockingQueue

        有界的队列,创建的时候必须要指定队列的大小,从源码可以看出构造的时候要传递值

    public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }
4.DelayQueue

        是一个延迟队列,无界、队列中每个元素都有过期时间,当从队列获取元素时,只有过期的元素才会出队,而队列头部是最早过期的元素,若是没有过期,则进行等待

拒绝策略

        AbortPolicy():队列满了,直接丢弃,并抛出异常

        CallerRunsPolicy():队列满了,直接丢弃任务,不抛出异常

        DiscardPolicy():队列满了,丢弃等待最久未处理的任务,并加入到等待队列中

        DiscardOldestPolicy():队列满了,直接在主线程中运行,不再进入线程池

使用风险

        1.死锁:两个或更多线程阻塞着等待其它处于死锁状态的线程所持有的锁,任何多线程应用程序都有死锁风险

        2.资源不足:线程消耗包括内存和其他系统资源在内的大量资源

        3.线程泄露:当从线程池中取出一个线程以执行任务,但任务完成后该线程没有返回池时,就会发生线程泄漏,如果这种情况发生次数足够多,线程池最终会为空,系统将停止,因为没有可用的线程来处理任务

创建方式

        Executors类(并发包)提供了4种创建线程池方法,这些方法最终都是通过配置ThreadPoolExecutor的不同参数,来达到不同的线程管理效果

newCacheTreadPool(可缓存)

        创建一个可以缓存的线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,没回收的话就新建线程

public static void main(String[] args)  {
    // 创建可缓存线程池
    ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
 
    for (int i = 0; i < 5; i++) {
        //创建任务
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            }
        };
        newCachedThreadPool.execute(runnable);
    }
}

        线程池的最大核心线程为无限大,当执行第二个任务时第一个任务已经完成,则会复用执行第一个任务的线程;如果第一个线程任务还没有完成则会新建一个线程

newFixedThread(固定大小)

        创建一个定长的线程池,可控制最大并发数,超出的线程进行队列等待

public static void main(String[] args)  {
    // 创建定长线程池
    ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
 
    for (int i = 0; i < 5; i++) {
        //创建任务
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            }
        };
        // 将任务交给线程池管理
        newFixedThreadPool.execute(runnable);
    }
}

        创建指定长度的线程池,任务超出当前线程池执行线程数量则会一直等待,直到运行。

newScheduleThreadPool(无限大小)

        可以创建定长的、支持定时任务,周期任务执行。

public static void main(String[] args)  {
    // 创建支持定时线程池
    ScheduledExecutorService  newScheduledThreadPool = Executors.newScheduledThreadPool(2);
 
    for (int i = 0; i < 5; i++) {
        //创建任务
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };
        // 将任务交给线程池管理,延迟2秒后才开始执行线程池中的所有任务
        newScheduledThreadPool.schedule(runnable, 2, TimeUnit.SECONDS);
    }
}

        以下案例中延迟2秒后开始执行线程池中的所有任务

newSingleExecutor(单线程)

        创建一个单线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

public static void main(String[] args)  {
    // 创建单线程-线程池,任务依次执行
    ExecutorService   newScheduledThreadPool = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 5; i++) {
        //创建任务
        Runnable runnable = new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };
        // 将任务交给线程池管理
        newScheduledThreadPool.execute(runnable);
    }
}

 ThreadPoolExecutor

/**
     * 用给定的初始参数创建一个新的ThreadPoolExecutor。
     */
    public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
                              int maximumPoolSize,//线程池的最大线程数
                              long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
                              ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
                              RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
                               ) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

 处理流程

 

线程池状态

线程池有五种状态:

1.RUNNING,运行状态,线程池创建完成后就是运行状态。

2.SHUTDOWN,关闭状态,执行shutdown()方法后进入此状态,继续处理队列中的任务,但是不再接收新的任务。

3.STOP,停止状态,shutdownNow()方法后进入此状态,不处理队列中的任务,也不接收新的任务。

4.TIDYING,整理状态,运行的线程数为0,队列中任务为空时,则进入此状态,进入此状态后会执行terminated()方法,进入销毁状态。

5.TERMINATED,销毁状态,执行terminated()方法,进入此状态

private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

线程配置

获取核心数:Runtime.getRuntime().availableProcessors()

IO密集型:

        判断程序中十分消耗IO的线程数,最大线程数一般设置为线程数的2倍

CPU密集型:

        判断电脑的核数,最大线程数设置为核数,可以保持cpu的效率最高

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java多线程线程池是一种重用线程的机制,它可以管理和调度多个线程来执行任务。使用线程池可以提高程序的性能和效率,同时也可以避免线程的频繁创建和销毁。 在Java中,可以使用线程池类ExecutorService和Executors来创建和管理线程池。具体步骤如下: 1. 创建一个线程池对象:可以使用Executors提供的静态方法创建不同类型的线程池,比如newFixedThreadPool固定大小线程池、newCachedThreadPool缓存线程池等。 2. 向线程池提交任务:使用submit方法向线程池提交需要执行的任务,也可以使用execute方法提交任务。任务可以是实现了Runnable接口或Callable接口的类,也可以是Lambda表达式。 3. 线程池执行任务:线程池会根据线程池的规模和任务的数量来调度和执行任务,多个任务会并发执行。 4. 关闭线程池:当不再需要线程池时,可以调用线程池的shutdown方法来关闭线程池,确保所有的任务都被执行完毕。 使用线程池的好处有: 1. 提高性能:线程池可以重用线程,避免线程频繁创建和销毁的开销,提高程序的性能。 2. 提供线程管理和调度:线程池可以管理和调度线程,根据线程池的规模和任务的数量来调度和执行任务。 3. 控制资源的使用:线程池可以限制并发线程的数量,避免过度占用系统资源。 在Java开发中,使用线程池是一种推荐的多线程编程方式,也是阿里巴巴在其《Java开发手册》中强制规定的做法。 Java线程的创建是依赖于系统内核的,通过JVM调用系统库创建内核线程,内核线程Java Thread是1:1的映射关系。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Java多线程(六):线程池详解](https://blog.csdn.net/m0_59140023/article/details/124436385)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [java多线程线程池](https://blog.csdn.net/qq_29996285/article/details/118955325)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值