java线程池运行原理

一、线程池优点

  1. 重用线程 :线程若频繁的创建销毁会给线程调度带来不小的额外工作量,而降低性能
  2. 控制线程数量 :线程数量过大 ,会导致系统资源开销大,每个线程都需要内存得以运行 过多的线程会导致CPU过度切换,导致整体并发性能降低

二、 创建线程池

  • java中常用的线程池:ThreadPoolExecutor
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 3, // 核心线程数2,最大线程数3
      10L, TimeUnit.SECONDS, // 空闲线程超过10s自动回收
      new ArrayBlockingQueue<>(2),// 使用有界队列,队列大小为2
      Executors.defaultThreadFactory(),// 使用默认的线程工厂创建线程
      new ThreadPoolExecutor.CallerRunsPolicy());// 指定由于达到线程边界和队列容量而在执行被阻止时使用的处理程序

  • 将任务交由线程池执行,有两种方式

    1. 第一种:void execute(Runnable command)

      • 执行没有返回值
      • 线程其他几种的执行逻辑依然是调用此方法执行
    2. 第二种:<T> Future<T> submit(Callable<T> task)

      public <T> Future<T> submit(Callable<T> task) {
         if (task == null) throw new NullPointerException();
         RunnableFuture<T> ftask = newTaskFor(task);
         // 调用execute方法
         execute(ftask);
         return ftask;
      }
      
      • 执行可以获取返回值
      • 包装成RunnableFuture通过execute()方法执行,并保存结果
      • 也可以直接使用 Runnable接口任务,最后会桥接成Callable形式,返回值可以传入也可使用默认的null
  • 由此我们应该发现,线程池执行原理的关键在于execute()方法

    // java.util.concurrent.ThreadPoolExecutor
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
    
        int c = ctl.get(); // 线程池状态,前3位表示运行状态,后29位表示线程数
        // 首先尝试添加核心线程来执行
        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); // 任务还处理不过来,执行丢弃任务操作
    }
    

    其中调用 addWorker(firstTask, code)方法创建工作线程处理

    // 两个参数,firstTask:新线程的第一个任务,core:是否创建核心线程
    private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
    
            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty()))
                return false;
    
            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c)) // 线程数成功增一,退出循环
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
    
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);// 创建新的工作线程
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());
    
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start(); // 线程启动
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
    
  • 线程启动后,必然是调用Workerrun()方法

// java.util.concurrent.ThreadPoolExecutor.Worker
public void run() {
    runWorker(this); // 调用runWorker方法
}
  
// java.util.concurrent.ThreadPoolExecutor.Worker
// Worker的runWorker
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        // 循环获取任务执行,其中getTask()方法进行了阻塞及超时处理
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run(); // 执行任务
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

  • 如果传人的任务为空或当前任务以执行完时会从队列中获取等待执行任务
// java.util.concurrent.ThreadPoolExecutor.Worker
// 从队列中获取任务
private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);

        // 判断此线程是否允许超时关闭
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c)) // 超时尝试修改线程数减一
                // 返回空,未获取到任务,在线程执行runWorker方法退出循环,线程结束
                return null;
            continue;
        }

        try {
            // 允许关闭则会根据设置的时间等待
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
            workQueue.take();
            if (r != null)
                return r;
            timedOut = true; // 设置为超时,下次循环结束此线程
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

三、总结

  1. 线程池初始化,设置的线程池的核心线程数、最大线程数、空闲线程的超时时间、提供任务队列等
  2. 线程池执行任务
    1. 将任务提交到线程池管理
    2. 线程池首先尝试将任务交给核心线程处理(addWorker(firstTask, true)),一般在线程数小于设定的核心线程数时都能成功创建一个线程执行当前任务
    3. 如若核心线程不能处理(如:现有线程大于核心线程数,大于线程池上限,线程池状态不对等),将任务添加到任务队列,在现有线程空闲时会轮询此队列,执行任务
    4. 如若任务队列也已放满,尝试创建额外的线程(addWorker(firstTask, false))处理,和创建核心线程一样,唯一的区别在于是现有线程数与核心线程数比较还是与最大线程数比较
    5. 额外的线程数也达上限,线程池无法处理,此时调用给定命令的拒绝执行处理程序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java线程池是一种用于管理和复用线程的机制,它可以提高多线程应用程序的性能和可靠性。线程池中的线程可以被重复使用,避免了频繁创建和销毁线程的开销。 Java线程池的工作原理如下: 1. 创建线程池:通过ThreadPoolExecutor类创建一个线程池对象,可以指定线程池的核心线程数、最大线程数、线程空闲时间等参数。 2. 提交任务:将任务提交给线程池,可以使用execute()方法提交Runnable任务,也可以使用submit()方法提交Callable任务。 3. 任务队列:线程池维护一个任务队列,用于存储提交的任务。如果当前线程池中的线程数小于核心线程数,线程池创建新的线程来执行任务;如果当前线程池中的线程数已经达到核心线程数,任务被放入任务队列等待执行。 4. 执行任务:当任务队列中有任务时,线程池中的空闲线程从任务队列中取出任务并执行。如果任务队列为空且当前线程池中的线程数超过核心线程数,空闲线程等待一段时间后被销毁。 5. 拒绝策略:如果任务队列已满且当前线程池中的线程数已达到最大线程数,新提交的任务根据指定的拒绝策略进行处理,常见的拒绝策略有抛出异常、丢弃任务、丢弃最旧的任务等。 6. 线程池状态:线程池有几种状态,包括运行、关闭、停止等。可以通过调用shutdown()方法来关闭线程池,调用shutdownNow()方法来停止线程池

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值