线程池

一、线程池

下面这几组大家应该很属于,加 s 的都是工具类
Array Arrays
Collection Collections
Executor Executors

List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
//上面和下面是等价的
List<String> list = Arrays.asList("a","b","c");

在这里插入图片描述

1.获取线程池的方法

1.1三种获取线程池的方法(但是,这三种在生产中都不允许使用!!!)

1.一池固定数线程
2.一池一线程
3.一池多线程

        1. ExecutorService executorService1 = Executors.newFixedThreadPool(5);
        2. ExecutorService executorService2 = Executors.newSingleThreadExecutor();
        3. ExecutorService executorService3 = Executors.newCachedThreadPool();

底层源码如下:
在这里插入图片描述
在这里插入图片描述
所有线程池底层都是调这个构造方法实现的

    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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

下面给大家分享一下七大参数的详解

corePoolSize:线程池中常驻核心线程数(比如:银行网点,每天默认只开两个窗口给客服办理业务)

maximumPoolSize:线程池能够同时容纳最大的线程数,必须大于等于1(比如:银行网点,最多只有五个窗口给客户办理业务)

keepAliveTime:多余线程的存活时间(比如:银行网点,每天默认只开两个窗口给客服办理业务,今天中午人很多,又临时开了三个窗口给客户办理业务,下午人又少了,60分钟内,没有人办理业务,临时窗口就关闭,一般个unit参数一起使用,一个控制数字,一个控制单位,组合控制时间长短)

unit:keepAliveTime的单位(解释在上面)

workQueue:任务队列,被提交但尚未执行(比如:银行网点的候客区)

threadFactory:表示生成线程池中工作线程的工厂,一般默认即可(比如:银行网点的HR,负责找员工过来上班)

handler:拒绝策略,表示队列满了,并且工作线程数等于线程池最大线程数了。(比如:银行网点,候客区人满了,没有座位了,并且五个窗口都已经开了,此时银行保安就会拒绝其他客户来办理业务)

2.JDK内置的拒绝策略

AbortPolicy(默认):直接抛出RejectedExecutionException异常,阻止系统正常执行
CallerRunsPolicy:“调用者运行”一种调用机制,该策略既不会抛出异常,也不会抛弃任务,而是将默些任务回退到调用者,从而降低新的任务流量
DiscardOldestPolicy:丢弃队列中等待最久的任务,然后把当前任务加入到队列中尝试重新提交任务
DiscardPolicy:直接丢任务,不抛任何异常。如果允许任务丢失,这是最好的策略。

3. 生产情况下,自己写线程池

先说说为什么我们不用内置的线程池
在这里插入图片描述
在这里插入图片描述
我们都知道创建线程需要一个阻塞队列,源码用的是LinkedBlockingQueue,我们又知道LinkedBlockingQueue是一个可以说是无界的队列,因为他的长度是Integer的最大值(2147483647),所有可以说他是一个无界的

3.1 手写线程池

下面我们开始写一个自己的线程池:

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */

import java.util.concurrent.*;

/**
 * 我的线程池
 *
 * @author yangjikang
 * @date 2019/6/19 10:39
 * @modified By yangjikang
 */
public class TestExecutor {

    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                2,
                5,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        try {
            for (int i = 0; i < 8; i++) {
                final String tempUser = i + "号客户";
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t 窗口给" + tempUser + "办理业务...");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            executorService.shutdown();
        }
    }
}

控制台效果图
在这里插入图片描述
上面,这段代码,我们是模拟8个客户来银行办理业务的场景。没有异常,属于正常情况

3.2 AbortPolicy拒绝策略

继续看下面的代码:

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */

import java.util.concurrent.*;

/**
 * 获取线程池
 *
 * @author yangjikang
 * @date 2019/6/19 10:39
 * @modified By yangjikang
 */
public class TestExecutor {

    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                2,
                5,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        try {
            for (int i = 0; i < 10; i++) {
                final String tempUser = i + "号客户";
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t 窗口给" + tempUser + "办理业务...");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            executorService.shutdown();
        }
    }
}

在这里插入图片描述
现在我模拟是个用户来办理业务就抛出了异常,为什么呢?以为我们自己写得线程池用的拒绝策略是AbortPolicy
最多只支持最大线程数(代码中是5)加上队列最大界限(代码中是3)的线程数(结果就是8),所以十个用户过来就会抛出RejectedExecutionException异常。

3.3 CallerRunsPolicy拒绝策略

继续看下面的代码:

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */

import java.util.concurrent.*;

/**
 * 获取线程池
 *
 * @author yangjikang
 * @date 2019/6/19 10:39
 * @modified By yangjikang
 */
public class TestExecutor {

    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                2,
                5,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());
        try {
            for (int i = 0; i < 10; i++) {
                final String tempUser = i + "号客户";
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t 窗口给" + tempUser + "办理业务...");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            executorService.shutdown();
        }
    }
}

在这里插入图片描述
为什么会有main线程呢?因为我们用的是CallerRunsPolicy拒绝策略
在这里插入图片描述
看一下我们上面介绍的含义,就是谁调用找谁处理,比如:A点的银行网点让你去B点的银行网点办理业务,B银行人满了,跟你说,A让你来的,你去找A办理业务

3.4 DiscardOldestPolicy拒绝策略

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */

import java.util.concurrent.*;

/**
 * 获取线程池
 *
 * @author yangjikang
 * @date 2019/6/19 10:39
 * @modified By yangjikang
 */
public class TestExecutor {

    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                2,
                5,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy());
        try {
            for (int i = 0; i < 10; i++) {
                final String tempUser = i + "号客户";
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t 窗口给" + tempUser + "办理业务...");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            executorService.shutdown();
        }
    }
}

在这里插入图片描述
2号和3号客户没有办理业务(等待最久的不处理)

3.5 DiscardOldestPolicy拒绝策略

/*
 * Copyright (C), 2013-2019, 天津大海云科技有限公司
 */

import java.util.concurrent.*;

/**
 * 获取线程池
 *
 * @author yangjikang
 * @date 2019/6/19 10:39
 * @modified By yangjikang
 */
public class TestExecutor {

    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(
                2,
                5,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());
        try {
            for (int i = 0; i < 10; i++) {
                final String tempUser = i + "号客户";
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "\t 窗口给" + tempUser + "办理业务...");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            executorService.shutdown();
        }
    }
}

在这里插入图片描述
8号和9号没有处理,直接抛弃,因为改线程池最多只能处理8个线程

4. 如何合理的分配线程数

4.1 CPU密集型(运算)

在这里插入图片描述

4.2 IO密集型(需要去数据库,redis等拿数据)

第一种
在这里插入图片描述
第二种
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值