线程池

个人备忘

前言 :

在java中我们开辟一个线程要么继承 Thread 类,要么 实现Runable 接口,其实我们自己的new 出来的这个子类或者实现他们不是线程,他们只是一个普通的java 对象是会被GC 回收的。只不过我们在执行start() 之后,虚拟机会帮我们申请开辟一个新的线程,该线程通过我们告知的子类对象,去回调我们重写的run() 。所以我们的线程池不是在管理我们的java对象。而是管理cpu 开辟出来的这块资源。这样当我们再次new 子类的时候,放到我们的线程池中,cpu 将不会再次开辟新的资源。而是继续使用线程池中的开辟好的资源。

什么时候是线程池?
1. 降低资源的消耗,避免线程重复的创建和销毁造成的资源消耗。
2. 提高响应速度,任务:T1创建线程时间,T2任务执行时间,T3线程销毁时间。如果将线程存放到线程池中,那么T1和T2都可以提前处理,任务只有T2 的执行时间。
3. 提高线程的管理。

一 为什么我们要用线程池?

  1. 线程的容器,管理器。
  2. 工作线程做具体的任务。
  3. 对外提供任务接口,可以让我们的客户端提交任务到线程池。
  4. 任务的容器,当线程池满了,我们要有自己的任务容器用来暂时存储其他任务,DelayQueue<>、list/map 等线程集合或者队列。

二 实现一个自己的线程池

<!-- 配置线程池 -->
    <bean id="threadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 线程池维护线程的最少数量 -->
        <property name="corePoolSize" value="2" />
        <!-- 线程池维护线程所允许的空闲时间 -->
        <property name="keepAliveSeconds" value="10000" />
        <!-- 线程池维护线程的最大数量 -->
        <property name="maxPoolSize" value="5" />
        <!-- 线程池所使用的缓冲队列 -->
        <property name="queueCapacity" value="50" />
    </bean>
private static void startThread() {
        LOG.info("==>startThread");

        threadPool.execute(new Runnable() {
            public void run() {
                try {
                    while (true) {
                        Thread.sleep(1000);
                        LOG.info("==>threadPool.getActiveCount():" + threadPool.getActiveCount());
                        LOG.info("==>threadPool.getMaxPoolSize():" + threadPool.getMaxPoolSize());
                        LOG.info("一秒间隔==>tasks.size():" + tasks.size());

                        // 如果当前活动线程等于最大线程,那么不执行
                        if (threadPool.getActiveCount() < threadPool.getMaxPoolSize()) {
                            LOG.info("==>tasks.size():" + tasks.size());
                            final NotifyTask task = tasks.take(); //使用take方法获取过期任务,如果获取不到,就一直等待,知道获取到数据
                            if (task != null) {
                                threadPool.execute(new Runnable() {
                                    public void run() {
                                        tasks.remove(task);
                                        task.run(); // 执行通知处理
                                        LOG.info("==>tasks.size():" + tasks.size());
                                    }
                                });
                            }
                        }
                    }
                } catch (Exception e) {
                    LOG.error("系统异常;", e);
                }
            }
        });
    }

三 线程池要做些什么?

  1. Execute 提交不需要返回值的任务。
  2. Submit 提交需要返回值的任务,返回值是个Futrue类型的对象,调用futrue的get方法来获取返回值。

四 提交任务

  1. ShutDown() : interrupt()方法来终止线程。
  2. ShutDownNow(),尝试停止所有正在执行的线程。

合理的配置线程池

  1. 线程数配置任务 :(1) cpu计算密集型,(2) IO密集型,混合型。
  2. (1) cpu 计算密集型 = 计算机cpu 个数 / 计算机cpu数+1 。这与操作系统有关,应付页缺失。ps : 空限度很高。
  3. 2) IO密集型 = 计算机cpu 个数 * 2 。
  4. 3)混合型 :拆分成计算密集型,IO密集型。
  5. 获取当前机器中的cpu核心个数:Runtime.getRuntime().availableProcessors() ; 可以用它 +1 或者 * 2 实现上面说的那两种类型。
  6. 一定要有有界队列,尽量不要使用无界队列。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值