Java线程池(原理与代码实现)-小白入门

Java线程池(原理与代码实现)-小白入门

作为一位程序员,多线程开发是必不可少的,对线程池也或多或少的有所了解,或者只是会用,对其原理却朦朦胧胧。
多线程技术主要解决处理器单元内多个线程执行的问题,可以显著减少处理器单元的闲置时间,增加处理器但愿的吞吐能力。

线程池是什么?

线程池由任务队列和工作线程组成,它可以重用线程来避免线程创建的开销,在任务过多时通过排队避免创建过多线程来减少资源的消耗与竞争,确保任务有序完成。简而言之,线程池就是事先将线程放到一个容器中,当使用线程的时候,不再去new出一个线程,而是直接从线程池取出来就可以了。
线程池的好处:

1.降低资源消耗:重复利用线程池中的线程节省线程创建与销毁带来的消耗;
2.提高性能:当任务需求时,可以不用创建线程直接执行,主要是直接从线程池中取出线程去执行
3.提高线程的可管理性:线程是稀缺资源,而且也是任务中不可缺少的资源,如果频繁的且无节制的创建会消耗系统资源,降低系统稳定性而导致系统崩溃,内存溢出等问题。

线程池如何使用

java.util.concurrent.Executors提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池
创建线程池的方式有以下四种:

  1. ExecutorService executors = Executors.newFixexThreadPool(n);创建固定大小的线程池,每提交一个任务就是一个线程,直到达到线程池的最大数量,然后进入等待队列直到前面的任务完成才能继续执行
  2. ExecutorService executors = Executors.newCachedThreadPool();创建可缓存的线程池,根据需要创建线程池,上限为操作系统的内存条大小【推荐使用】
  3. ExecutorService executors = Executors.newSingleThreadExecutor();创建单个线程的线程池,即单线程串行执行任务
  4. ScheduleExecutorService executors = Executors.newScheduledThreadPool();创建调度线程池,没有大小限制,若使用不当,可能会出现内存溢出,程序中断等情况。
    使用上述创建方法创建后,通过execute()方法启动线程池。

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具,真正的线程池接口是ExecutorService。
比较重要的几个类:

ExecutorService真正的线程池接口
ThreadPoolExecutorExecutorService的默认实现。
ScheduledExecutorService能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。
ScheduledThreadPoolExecutor继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。

ThreadPoolExecutor详解

ThreadPoolExecutor的完整构造方法为:

//有多个构造方法,最终都指向这个最多参数的构造方法
  public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

corePoolSize:池中所保存的线程数,包括空闲线程;
maximumPoolSize:池中允许的最大线程数;
keepAliveTime:默认是 0,当线程没有任务处理后空闲线程保持多长时间,不推荐使用;
unit:keepAliveTime 参数的时间单位;
workQueue:任务等待队列,当达到 corePoolSize的时候就向该等待队列放入线程信息(默认为一个LinkedBlockingQueue);
threadFactory:是构造 Thread 的方法,一个接口类,可以使用默认的 default实现,也可以自己去包装和传递,主要实现 newThread 方法即可。即执行程序创建新线程时使用的工厂。
defaultHandler:当参数 maximumPoolSize 达到后丢弃处理的方法实现,java 提供了 5种丢弃处理的方法,当然也可以自己弄,主要是要实现接口 RejectedExecutionHandler 中rejectedExecution(Runnabler, ThreadPoolExecutor e) 方法,java 默认使用的是AbortPolicy,他的作用是当出现这种情况的时候抛出一个异常;通常得到线程池后会调用其中的 submit 或 execute 方法去提交执行异步任务,其实 submit 方法最终会调用execute 方法来进行操作,只是他提供了一个 Future来托管返回值的处理而已,当你调用需要有返回值的信息时用它来处理是比较好的,这个 Future 会包装 Callable 信息。

代码实现

package threadTest;

import java.util.concurrent.*;

public class ThreadPoolTest {
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    private static final int CORE_POOL_SIZE = Math.max(4, Math.min(CPU_COUNT - 1, 5));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 2;
    private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<>(10);


    public static void main(String[] args) {
        System.out.println("核心线程数=" + CORE_POOL_SIZE);
        System.out.println("最大线程数=" + MAXIMUM_POOL_SIZE);

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,  //核心线程数
                MAXIMUM_POOL_SIZE, //线程池中最大的线程数
                60,  //线程的存活时间,没事干的时候,空闲的时间
                TimeUnit.SECONDS, //线程存活时间的单位
                sPoolWorkQueue, //线程缓存队列
                new ThreadFactory() {  //线程创建工厂,如果线程池需要创建线程会调用newThread来创建
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r);
                        thread.setDaemon(false);
                        return thread;
                    }
                });
        threadPoolExecutor.allowCoreThreadTimeOut(true);

        for (int i = 0; i < 20; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("执行完毕" + Thread.currentThread().getName());
                }

            };
            //丢给线程池去执行
            threadPoolExecutor.execute(runnable);
        }
    }
}

结果显示:
在这里插入图片描述
参考代码:https://www.imooc.com/article/51147

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值