线程与线程池

线程

线程是操作系统能够运算调度的最小单位,它被包含在进程中,是进程中的实际运做单位。

https://baike.baidu.com/item/线程/103101?fr=aladdin

Java创建线程的方式

public class DemoThread extends Thread {
    public static void main(String[] args) throws Exception {
        //1、继承Thread类
        Thread t1 = new DemoThread();
        //2、使用Runnable接口
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
            //...
            }
        });
        //Thread t2 = new Thread(()->System.out.println(""));
        //3、使用Callable
        Future<String> future = new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() {
                return null;
            }
        });
        t1.start();
        t2.start();
        future.get();
    }
    @Override
    public void run() {
        //...
    }
}

线程池

为什么要使用线程池

  1. 降低资源的消耗,通过重复利用已创建的线程降低线程创建、销毁线程造成的消耗。
  2. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控

线程池参数

 /**
     * @param corePoolSize 核心线程数
     * @param maximumPoolSize 最大线程数
     * @param keepAliveTime 非核心线程数最大存活时间
     * @param unit 存活时间单位
     * @param workQueue Runnable类型的阻塞队列
     * @param threadFactory 线程工厂,负责创建线程
     * @param handler 工作队列饱和后,任务的拒绝策略
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    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;
    }

拒绝策略

线程池拒绝策略需要实现java.util.concurrent.RejectedExecutionHandler接口,默认提供4种拒绝策略

  1. CallerRunsPolicy:被拒绝的任务在主线程中运行,所以主线程就被阻塞了。
  2. AbortPolicy:抛出RejectedExecutionException 异常,也是默认的拒绝策略
  3. DiscardPolicy:直接丢弃
  4. DiscardOldestPolicy:丢弃最早进入的任务

使用Executors创建线程池

  1. newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  2. newSingleThreadExecutor:创建一个单线程化的线程池执行任务。
  3. newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  4. newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。

添加任务执行的逻辑

public void execute(Runnable command) {
  if (command == null)
    throw new NullPointerException(); 
  int c = ctl.get();
  //判断工作线程与核心线程数量
  if (workerCountOf(c) < corePoolSize) {
    //如果当前工作线程数小于核心线程数,创建核心线程执行任务,创建成功返回
    if (addWorker(command, true))
      return;
    //添加核心线程失败,获取当前之下状态
    c = ctl.get();
  }
  //如果当前线程池在运行且添加队列成功
  if (isRunning(c) && workQueue.offer(command)) {
    int recheck = ctl.get();
    //如果当前线程池未运行且移出任务成功,执行拒绝策略
    if (! isRunning(recheck) && remove(command))
      reject(command);
    //创建非核心线程执行
    else if (workerCountOf(recheck) == 0)
      addWorker(null, false);
  }
  //创建非核心线程执行,如果创建失败执行拒绝策略
  else if (!addWorker(command, false))
    reject(command);
 }
posted @ 2021-01-21 22:41  往事随雨  阅读(51)  评论(0)    收藏  举报