线程池

并发与并行

并发:并发就是指代码逻辑上可以并行,有并行的潜力,但是不一定当前是真的以物理并行的方式运行
例如:在吃饭的时候,来电话了,去接电话,这种方式就是 支持并发

并行:并行是指在同一时刻运行多个程序,比如程序的进程。
例如:程序在同一时刻运行着QQ,微信等程序,是相对于cpu的多核处理来说的,是以物理方式运行的。

线程池

①.线程池的整体结构

在这里插入图片描述
上图主要是展示线程池的继承结构和其中用到的队列结构

②.线程池的创建

说起来线程池的创建,就不得不说,ThreadPoolExecutor。创建线程池就是通过new ThreadPoolExecutor()进行创建。下面就说下 ThreadPoolExecutor的几个核心参数。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • corePoolSize:
    该线程池中核心线程数最大值。线程池新建线程的时候,如果当前线程总数小于 corePoolSize ,则新建的是核心线程;如果超过corePoolSize,则新建的是非核心线程。核心线程数默认是一直存在于线程池中的,即使啥也不干。如果在任务执行过程中,所有的核心线程都在进行工作,此时创建的线程是非核心线程,非核心线程会加入到队列中处理任务,处理完毕之后就会被销毁。
  • maximumPoolSize:该线程池中线程总数的最大值。
  • keepAliveTime:
    该线程池中非核心线程闲置超时时长。一个非核心线程,如果不干活(闲置状态)的时长,超过这个参数所设定的时长,就会被销毁掉。
  • unit:
    MILLISECONDS:1毫秒 、SECONDS:秒、MINUTES:分、HOURS:小时、DAYS:天
  • workQueue:
    该线程池中的任务队列:维护着等待执行的Runnable对象。当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务
  • threadFactory:
    在创建线程池的时候,默认是使用 Executors.defaultThreadFactory()
  • handler:拒绝策略。默认是new AbortPolicy();
    1、当你设置的任务缓存队列过小的时候,或者说, 你的线程池里面所有的线程都在干活(线程数== maxPoolSize),并且你的任务缓存队列也已经充满了等待的队列, 这个时候,你再向它提交任务,则会抛出这个异常。
    2、执行shutdown后再向线程池中添加任务。

创建线程池的方式有很多种,可以通过 new ThreadPoolExecutor()进行创建,也可以通过Executors进行创建。

通过new ThreadPoolExecutor()进行创建
    public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6) {
        this(var1, var2, var3, var5, var6, Executors.defaultThreadFactory(), defaultHandler);
    }

    public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6, ThreadFactory var7) {
        this(var1, var2, var3, var5, var6, var7, defaultHandler);
    }

    public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6, RejectedExecutionHandler var7) {
        this(var1, var2, var3, var5, var6, Executors.defaultThreadFactory(), var7);
    }

    public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6, ThreadFactory var7, RejectedExecutionHandler var8) {
        this.ctl = new AtomicInteger(ctlOf(-536870912, 0));
        this.mainLock = new ReentrantLock();
        this.workers = new HashSet();
        this.termination = this.mainLock.newCondition();
        if (var1 >= 0 && var2 > 0 && var2 >= var1 && var3 >= 0L) {
            if (var6 != null && var7 != null && var8 != null) {
                this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
                this.corePoolSize = var1;
                this.maximumPoolSize = var2;
                this.workQueue = var6;
                this.keepAliveTime = var5.toNanos(var3);
                this.threadFactory = var7;
                this.handler = var8;
            } else {
                throw new NullPointerException();
            }
        } else {
            throw new IllegalArgumentException();
        }
    }
    <br/>
通过Executors进行创建
	// 创建固定大小的线程池
	public static ExecutorService newFixedThreadPool(int var0) {
        return new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
    }

	public static ExecutorService newFixedThreadPool(int var0, ThreadFactory var1) {
        return new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), var1);
    }

	// 创建一个线程的线程池
	public static ExecutorService newSingleThreadExecutor() {
        return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
    }

    public static ExecutorService newSingleThreadExecutor(ThreadFactory var0) {
        return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), var0));
    }

	// 创建可缓存大小的线程池
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue());
    }

    public static ExecutorService newCachedThreadPool(ThreadFactory var0) {
        return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue(), var0);
    }

	// 创建具有一个线程的,能够延时执行任务和周期的线程池
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
    }

    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory var0) {
        return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1, var0));
    }
	
	// 创建一个能够延时执行任务和周期的线程池
    public static ScheduledExecutorService newScheduledThreadPool(int var0) {
        return new ScheduledThreadPoolExecutor(var0);
    }

    public static ScheduledExecutorService newScheduledThreadPool(int var0, ThreadFactory var1) {
        return new ScheduledThreadPoolExecutor(var0, var1);

但是,通过Executors创建线程池是不推荐的使用的,原因如下:
newCachedThreadPool() 会默认设置核心线程数为0,线程总数为Integer.MAX_SIZE大小的线程池。
newFixedThreadPool()的时候,new LinkedBlockingQueue()也会设置Integer.MAX_SIZE的队列。
上述2种行为在高并发的情况下会导致出现 OOM异常,因此不推荐使用。如果要创建线程池,直接通过new ThreadPoolExecuor() 创建即可

线程池提交线程

ExecutorService executor = Excutors.newFixedThreadPollExecutor(100);
submit():

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

execute():

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

由源码可以看出,其实调用submit的时候,底层还是调用了execute()方法,只不过submit提交之后是有返回值的,调用是成功,还是失败,都可以获取到

线程池的队列

一般来说,workQueue有以下四种队列类型:

  • SynchronousQueue:(同步队列)
    这个队列接收到任务的时候,会直接提交给线程处理,而不保留它(名字定义为 同步队列)。但有一种情况,假设所有线程都在工作怎么办?

    这种情况下,SynchronousQueue就会新建一个线程来处理这个任务。所以为了保证不出现(线程数达到了maximumPoolSize而不能新建线程)的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大,去规避这个使用风险。

  • LinkedBlockingQueue(链表阻塞队列)
    这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize

参考文章:https://www.jianshu.com/p/50fffbf21b39

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值