概述

线程池就是一个可以复用线程的技术

不使用线程池的问题:

用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了又要创建新线程处理,而创建新线程的开销很大,而且请求过多会产生大量的线程出来,会严重影响系统性能

核心线程:一直工作的线程数。

任务队列:实现了Runnable、Callable的接口

创建线程池

ExecutorService接口

线程池_System

注意事项:

新任务提交时发现核心线程都在忙,任务队列也满了,而且还可以创建临时线程,这时才会创建临时线程。

核心线程和临时现场都满了,任务队列也满了,还有新任务到来,就会拒绝新任务。

创建线程池执行Runnable任务

线程池_线程池_02

public class test {
    public static void main(String[] args) {
        // 1. 通过ThreadPoolExecutor创建一个线程池对象。
        ExecutorService pool = new ThreadPoolExecutor(
            3, // corePoolSize: 核心线程数
            5, // maximumPoolSize: 最大线程数
            8, // keepAliveTime: 空闲线程存活时间
            TimeUnit.SECONDS, // 时间单位
            new ArrayBlockingQueue<>(4), // 阻塞队列
            Executors.defaultThreadFactory(), // 默认线程工厂
            new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
        );

        Runnable target = new MyRunnable();

        pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
        pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
        pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
        pool.execute(target); // 复用线程池里的线程
        pool.execute(target); // 复用线程池里的线程

        // pool.shutdown(); // 关闭线程池:等待全部任务执行完毕后,再关闭线程池
        // pool.shutdownNow(); // 立即关闭线程池:不管任务是否已执行完毕!
    }
}
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is running");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

创建临时线程时机

pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
pool.execute(target); 
pool.execute(target);
pool.execute(target);
pool.execute(target);
//创建临时线程
pool.execute(target);
pool.execute(target);

拒绝新任务时机

pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
//创建临时线程
pool.execute(target);
pool.execute(target);
pool.execute(target);//拒绝

线程池_System_03

创建线程池处理Callable任务

public class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1. 通过ThreadPoolExecutor创建一个线程池对象。
        ExecutorService pool = new ThreadPoolExecutor(
            3, // corePoolSize: 核心线程数
            5, // maximumPoolSize: 最大线程数
            8, // keepAliveTime: 空闲线程存活时间
            TimeUnit.SECONDS, // 时间单位
            new ArrayBlockingQueue<>(4), // 阻塞队列
            Executors.defaultThreadFactory(), // 默认线程工厂
            new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
        );

//        Runnable target = new MyRunnable();
//
//        pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
//        pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
//        pool.execute(target); // 会分配自动创建一个新线程,自动处理这个任务,自动执行的!
//        pool.execute(target);
//        pool.execute(target);
//        pool.execute(target);
//        pool.execute(target);
//        //创建临时线程
//        pool.execute(target);
//        pool.execute(target);
//        pool.execute(target);//拒绝

        // 2. 使用线程处理Callable任务。
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());


        // pool.shutdown(); // 关闭线程池:等待全部任务执行完毕后,再关闭线程池
        // pool.shutdownNow(); // 立即关闭线程池:不管任务是否已执行完毕!
    }
}
public class MyCallable implements Callable<String> {
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }
    @Override
    public String call() throws Exception {
        //线程任务,返回结果
//        需求:求1~n的和,并返回
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += i;
        }
        return "1~" + n + "的和为:" + sum;
    }
}

Executors工具类实现线程池

Executors是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象。

线程池_线程池_04

可以更方便创建,不用写七个变量。但是,大型并发系统不允许使用这种方法

线程池_任务队列_05

核心线程数配置

计算密集型:核心线程数=CPU核数+1;

IO密集型:核心线程数=CPU核数*2.

其他

并发和并行

进程:运行的一个程序就是一个独立的进程。

线程属于进程的,一个进程中可以运行很多线程。

并发:进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程数量有限,为了保证所有线程都能进行,CPU会轮询为系统的每个线程服务,由于CPU的切换速度很快,给我们感觉在同时进行,称之为并发。

并行:在同一时刻,同时有多个线程在被CPU调度执行。这是真正在同时执行。

多线程执行是并发和并行同时执行。

线程的生命周期

线程从生到死的过程中,经历的各种状态及状态转换。

理解线程这些状态有利于提升并发编程的理解能力。

java状态有六种

线程池_任务队列_06

线程池_System_07