Java线程池

Java内置线程池

线程池有几个核心参数:1、核心线程数 2、最大线程数 3、阻塞队列

1、线程池创建时,不会创建线程。

2、当有任务到来时,如果当前执行线程数少于核心线程数,会创建线程执行,不管是否有其它线程正在执行。

3、如果当前执行线程数等于核心线程数,新来的线程会进入阻塞队列。

4、如果阻塞队列已经满了,而且当前线程数小于核心线程数,会开启新线程先执行执行新到来的任务,当其它线程执行完毕时会从阻塞队列中取出任务执行。

5、如果当前正在执行的线程等于最大线程数,且阻塞队列已满则会执行拒绝策略。

对于第二点,测试代码如下:

public class ThreadPoolTest implements Runnable {

    private int number;

    public ThreadPoolTest(int number){
        this.number = number;
    }

    public void run() {
        try {
            System.out.println("线程"+Thread.currentThread().getName()+"执行完毕="+number);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1));

        // 当前执行线程数0
        System.out.println("当前执行线程数:"+executor.getActiveCount());

        int i = 0;
        executor.submit(new ThreadPoolTest(i));

      	// 等待第一个线程执行完毕
        Thread.sleep(1000);

        i++;
        executor.submit(new ThreadPoolTest(i));

        Thread.sleep(100000);
        executor.shutdown();
    }
}

对于第三点,测试代码如下:

public class ThreadPoolTest implements Runnable {

    private int number;

    public ThreadPoolTest(int number){
        this.number = number;
    }

    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println("线程"+Thread.currentThread().getName()+"执行完毕="+number);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1));

        // 当前执行线程数0
        System.out.println("当前执行线程数:"+executor.getActiveCount());

        int i = 0;
        for (; i < 3; i++) {
            executor.submit(new ThreadPoolTest(i));
        }

        Thread.sleep(100000);
        executor.shutdown();
    }
}

对于第四点,测试代码如下:

public class ThreadPoolTest implements Runnable {

    private int number;

    public ThreadPoolTest(int number){
        this.number = number;
    }

    public void run() {
        try {
            Thread.sleep(5500);
            System.out.println("线程"+Thread.currentThread().getName()+"执行完毕="+number);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1));

        // 当前执行线程数0
        System.out.println("当前执行线程数:"+executor.getActiveCount());

        int i = 0;
        for (; i < 4; i++) {
            executor.submit(new ThreadPoolTest(i));
        }
    }
}

对于第五点,测试代码如下:

public class ThreadPoolTest implements Runnable {

    private int number;

    public ThreadPoolTest(int number){
        this.number = number;
    }

    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println("线程"+Thread.currentThread().getName()+"执行完毕="+number);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 1000, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1));

        // 当前执行线程数0
        System.out.println("当前执行线程数:"+executor.getActiveCount());

        int i = 0;
        for (; i < 6; i++) {
            executor.submit(new ThreadPoolTest(i));
        }

        Thread.sleep(100000);
        executor.shutdown();
    }
}

Tomcat线程池

Tomcat线程池类是:org.apache.tomcat.util.threads.ThreadPoolExecutor

跑上面的测试代码,会发现和Java的线程池存在不同,主要体现在第3,4,5点上关于阻塞队列。

Tomcat的线程池在当前执行线程数量不超过最大线程数量时,会直接开启新线程执行,只有当线程数等于最大线程数量时,才会将请求进行排队,等到队列满了的时候,会执行拒绝策略。

对于Java内置线程的改动主要体现在TaskQueue队列上,默认的Java线程池在核心线程满了之后会将任务放在阻塞队列上,Tomcat线程池继承拓展了Java线程池,并提供了TaskQueue的阻塞队列实现,重写了队列的offer方法,在判断当前线程数小于最大线程数时,offer方法会返回false,导致默认的Java线程池去创建新的线程执行任务。

代码如下:

// java.util.concurrent.ThreadPoolExecutor
public void execute(Runnable command) {
  // 省略部分代码
  // 主要看下面的if中workQueue.offer(command),当前线程数小于最大线程数时,这里返回了false
  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);
}

// org.apache.tomcat.util.threads.TaskQueue
public boolean offer(Runnable o) {
  // 省略部分代码
  
  // 主要是这里,这里的parent是线程池对象,创建队列时tomcat注入了线程池对象
  //if we have less threads than maximum force creation of a new thread
  if (parent.getPoolSize()<parent.getMaximumPoolSize()) {
    return false;
  }
  //if we reached here, we need to add it to the queue
  return super.offer(o);
}
posted @ 2022-09-24 00:55  zanpocc  阅读(35)  评论(0)    收藏  举报