zoukankan      html  css  js  c++  java
  • java多线程与线程池-copy

    1. 场景描述

    以前多线程也常用,这次因需再页面上用到多线程,如下图,总结下,有需要的朋友可以参考下。

    2. 解决方案

    2.1 线程池概念

    线程池官方定义不说了,通俗说下:池子的概念,事先(预定义)创建后,后续的线程可以直接从池子中拿,好处:

    (1)来创建线程比较消耗资源,不用重复创建;

    (2)池子事先定义好,避免无节制创建线程,导致系统出现不可预测风险。

    2.2 创建方式

    采用jdk自带的线程池创建方式,jdk1.5开始提供,在java.util.concurrent 的包下面。

    表面上有两种创建方式,其实一种。

    (1)一种是采用new ThreadPoolExecutor进行创建;

      public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) {
    

    (2)一种是采用Executors.newFixedThreadPool(3),不过还是调用的new ThreadPoolExecutor进行的线程池创建,赋值了几个默认参数而已。

    new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
    

    2.3 参数含义

    一共有 7 个参数:

    (1)corePoolSize

    核心线程数,当有任务进来的时候,如果当前线程数还未达到 corePoolSize 个数,则创建核心线程,核心线程有几个特点:

    1、当线程数未达到核心线程最大值的时候,新任务进来,即使有空闲线程,也不会复用,仍然新建核心线程;2、核心线程一般不会被销毁,即使是空闲的状态,但是如果通过方法 allowCoreThreadTimeOut(boolean value) 设置为 true 时,超时也同样会被销毁;3、生产环境首次初始化的时候,可以调用 prestartCoreThread() 方法来预先创建所有核心线程,避免第一次调用缓慢;

    (2)maximumPoolSize

    除了有核心线程外,有些策略是当核心线程完全无空闲的时候,还会创建一些临时的线程来处理任务,maximumPoolSize 就是核心线程 + 临时线程的最大上限。临时线程有一个超时机制,超过了设置的空闲时间没有事儿干,就会被销毁。

    (3)keepAliveTime

    这个就是上面两个参数里所提到的超时时间,也就是线程的最大空闲时间,默认用于非核心线程,通过 allowCoreThreadTimeOut(boolean value) 方法设置后,也会用于核心线程。

    (4)unit

    这个参数配合上面的 keepAliveTime ,指定超时的时间单位,秒、分、时等。

    (5)workQueue

    等待执行的任务队列,如果核心线程没有空闲的了,新来的任务就会被放到这个等待队列中。

    (6)threadFactory

    它是一个接口,用于实现生成线程的方式、定义线程名格式、是否后台执行等等,可以用 Executors.defaultThreadFactory() 默认的实现即可,也可以用 Guava 等三方库提供的方法实现,如果有特殊要求的话可以自己定义。它最重要的地方应该就是定义线程名称的格式,便于排查问题了吧。

    (7)handler

    当没有空闲的线程处理任务,并且等待队列已满(当然这只对有界队列有效),再有新任务进来的话,就要做一些取舍了,而这个参数就是指定取舍策略的,有下面四种策略可以选择:

    ThreadPoolExecutor.AbortPolicy:直接抛出异常,这是默认策略;
    ThreadPoolExecutor.DiscardPolicy:直接丢弃任务,但是不抛出异常。
    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后将新来的任务加入等待队列
    ThreadPoolExecutor.CallerRunsPolicy:由线程池所在的线程处理该任务,比如在 main 函数中创建线程池,如果执行此策略,将有 main 线程来执行该任务

    2.4 测试验证

    2.4.1 测试线程
    package com.yutong.laowang.test;
    
    public class ThreadTest extends Thread{
        @Override
        public void run() {
            System.out.println("软件老王:" +Thread.currentThread().getName());
      }
    }
    
    2.4.2 Executors创建
      private static void test4() {
            Executor mExecutor = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 10; i++) {
                Thread thread = new ThreadTest();
                mExecutor.execute(thread);
            }
        }
    

    结果:

    软件老王:pool-2-thread-2
    软件老王:pool-2-thread-3
    软件老王:pool-2-thread-1
    软件老王:pool-2-thread-3
    软件老王:pool-2-thread-2
    软件老王:pool-2-thread-1
    软件老王:pool-2-thread-3
    软件老王:pool-2-thread-2
    软件老王:pool-2-thread-3
    软件老王:pool-2-thread-1
    
    2.4.3 ThreadPoolExecutor创建
     private static void test3() {
            int poolSize = 5;
            int queueSize = 100;
            ExecutorService executorService = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.SECONDS,
                    new ArrayBlockingQueue<Runnable>(queueSize), new ThreadPoolExecutor.AbortPolicy());
                    
            for (int i=0;i<10;i++) {
                executorService.submit(new ThreadTest());
            }
        }
    

    结果:

    软件老王:pool-2-thread-1
    软件老王:pool-2-thread-3
    软件老王:pool-2-thread-4
    软件老王:pool-2-thread-2
    软件老王:pool-2-thread-5
    软件老王:pool-2-thread-5
    软件老王:pool-2-thread-1
    软件老王:pool-2-thread-2
    软件老王:pool-2-thread-2
    软件老王:pool-2-thread-1
    
    2.4.4 线程停用
    thread.interrupt();
    ---有时候不一定能执行成功,一般会结合判断使用,软件老王,例如:
    在ThreadTest类中进行判断,默认为false,当满足条件下为true,停用线程。
     public volatile boolean exit = false;
    
  • 相关阅读:
    【转】微信小程序原理
    【转】onAttachedToWindow()在整个Activity生命周期的位置及使用
    中序遍历非递归遍历算法
    多项式加法运算
    中缀表达式转换为后缀表达式
    多项式计算
    最大子列和问题
    广度优先搜索
    广搜和深搜的区别
    cookie 与 session 的区别详解
  • 原文地址:https://www.cnblogs.com/hanease/p/14515285.html
Copyright © 2011-2022 走看看