线程池01--基础使用

1. 快速入门

/**
 * 线程池快速入门
 *
 */
class Student{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class ThreadPool01 {
    //需求:登记学生的名字、年龄信息
    public static void main(String[] args) throws InterruptedException {
        List<Student> list = new ArrayList<>();
        for(int i =0;i<100;i++){
            list.add(new Student("小赵"+i,10));
        }

        long start = System.currentTimeMillis();
        //处理学生信息
        list.forEach(student -> {
            //TODO 登记学生信息
            ThreadHelper.sleep(10);
            System.out.println(student);
        });
        System.out.println("单线程处理时间:"+(System.currentTimeMillis()-start));

        //创建5个线程的线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        CountDownLatch countDownLatch = new CountDownLatch(100);
        for (Student student : list) {
            //execute 提交任务,接收一个Runnable类型的对象,内部调用其run方法,执行任务
            pool.execute(() -> {
                ThreadHelper.sleep(10);
                System.out.println(student);
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        System.out.println("线程池处理时间:"+(System.currentTimeMillis()-start));
        pool.shutdown();//关闭线程池
    }
}

2. 线程池介绍

1. 几种常见的线程池

/**
 * 常用的几种线程池
 */
class Task implements Runnable{
    int taksNum;//任务编号

    public Task(int taksNum) {
        this.taksNum = taksNum;
    }

    @Override
    public void run() {
        ThreadHelper.sleep(10);
        String name = Thread.currentThread().getName();
        System.out.println("任务"+taksNum+"被"+name+"执行。。。。。。");
    }
}
public class ThreadPool02 {
    public static void main(String[] args) throws InterruptedException {
        // 1. 创建固定线程数的线程池,可控制线程最大并发数,超出的线程数量的任务,会在队列中等待
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 1; i < 11; i++) {
            pool.execute(new Task(i));
        }
        ThreadHelper.sleep(5000L);//主线程等待
        pool.shutdown();

        // 2. 创建单个线程的线程池,保证所有任务按照指定顺序,如果处理任务的过程中报错,会创建一个新的线程
//        ExecutorService pool = Executors.newSingleThreadExecutor();
//        for (int i = 1; i < 11; i++) {
//            pool.execute(new Task(i));
//        }
//        pool.shutdown();

        // 3. 创建一个不限制数量的线程池,如果所有线程都在工作且又有新的任务,会创建新的线程,如果有线程空闲,就复用,线程空闲60s回收
        //    比较适合处理执行时间比较短的任务
//        ExecutorService pool = Executors.newCachedThreadPool();
//        for (int i = 1; i < 11; i++) {
//            pool.execute(new Task(i));
//        }
//        ThreadHelper.sleep(6000L);//主线程等待
//        pool.shutdown();
//
//        // 4. 创建拥有固定线程数量的定时线程任务的线程池
//        ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
//        System.out.println("当前时间:" + System.currentTimeMillis());
//        for (int i = 1; i < 2; i++) {
//            // a. 延期执行
            pool.schedule(new Task(i),3, TimeUnit.SECONDS);// 延期3秒执行
//
//            // b. 周期执行
//            pool.scheduleAtFixedRate(new Task(i),3,1, TimeUnit.SECONDS);// 延期3秒钟后,每隔1秒执行一次任务
            pool.scheduleWithFixedDelay(new Task(i),3,1, TimeUnit.SECONDS);// 延期3秒钟执行,上次任务执行结束1秒后,本次任务开始执行
//        }
//        ThreadHelper.sleep(60000L);//主线程等待
//        pool.shutdown();
    }

面试题:单个线程池和固定数量的设置为1,有什么区别?

    1. newFixedThreadPool返回的是 ThreadPoolExecutor 对象,newSingleThreadExecutor返回的是 FinalizableDelegatedExecutorService,对 ThreadPoolExecutor 做了一层封装
    2. FinalizableDelegatedExecutorService相对ThreadPoolExecutor来说,提供的方法更少,保证了一旦被创建就永远只能为单线程

1. 主要参数

corePoolSize

核心线程数量

maximumPoolSize

最大线程数量

keepAliveTime

没有任务时,线程最多存活的时间,超过这个时间就被终止了。

默认情况下,只有在线程池线程数量超出corePoolSize,才会把超时的空闲线程给停止掉,

否则保持线程池中有 corePoolSize 个线程

unit

参数keepAliveTime的时间单位,就是 TimeUnit类当中的几个属性

workQueue

用来存储待执行任务的队列,有以下几种:

  • ArrayBlockingQueue:基于数组的队列,创建时需要指定大小。
  • LinkedBlockingQueue:基于链表的队列,如果没有指定大小,则默认值是 Integer.MAX_VALUE。(newFixedThreadPool和newSingleThreadExecutor使用的就是这种队列)。
  • SynchronousQueue:这种队列比较特殊,在某次添加元素后必须等待其他线程取走后才能继续添加,可以认为SynchronousQueue是一个缓存值为1的阻塞队列(newCachedThreadPool使用的就是这种队列)。

threadFactory

线程工厂,用来创建线程。

Handler

拒绝策略,有以下几种:

  • ThreadPoolExecutor.AbortPolicy:丢弃任务,抛出 RejectedExecutionException 异常,默认值
  • ThreadPoolExecutor.DiscardPolicy:丢弃任务,不抛异常。
  • ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最老的任务,尝试新任务。
  • ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用 execute方法的线程执行该任务。

2. 执行流程、原理

开始时,每来一个任务创建一个线程执行,直到线程数达到核心线程数,再来任务就放到队列中,如果队列满了,继续创建线程执行,直到线程数达到最大线程数,如果还有任务,就执行拒绝策略。

当没有任务时且线程数量大于核心线程数时,多余的线程的空闲时间超过了keepAliveTime,那么这个线程就要被销毁了,直到线程数量达到核心线程数

注意:我们传进去的任务对象是Runnable类型的,但最终是以 对象.run() 的方式运行的

3. 主要方法

void execute(Runnable task):接收Runnable类型的任务对象,没有返回值

如果异常,直接抛出

Future<?> submit(Runnable task):接收Runnable类型的任务对象,返回Future对象

如果异常,调用future对象的get方法时才会报错

<T> Future<T> submit(Runnable task, T result) :如果成功,调用get方法能够得到传进去的result对象

<T> Future<T> submit(Callable<T> task):接收Callable类型的任务对象,如果成功,调用get方法能够得到返回值

shutdown:让线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕

shutdownNow:让线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。

3. 设置合理的线程数

/**
 * 设置合理的线程数量
 *      1.计算密集型,又称CPU密集型,比如:数据都在内存中,需要读数据进行处理、运算、组装,线程不会阻塞,这时候压榨CPU性能,
 *          CPU核数+1
 *
 *      2.IO密集型,线程阻塞或等待,比如:数据库读写,磁盘文件读写
 *          CPU核数 * 2
 *          CPU核数 / (1 – 阻塞系数)(0.8~0.9之间)
 *
 *      通用公式:(1 + 线程等待时间/线程CPU时间)*CPU利用率*CPU数量
 *
 *      3. 混合型,先考虑需不需要拆分,然后在挨个测试
 *
 *      4. 监控系统资源,动态修改(传说GO语言可以实现)
 *
 * 注意:最终数量都应该通过实际不断测试得出,各种公式只是参考
 *
 */
public class ThreadPool05 {
    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().availableProcessors());//输出可用的cup个数
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值