线程池学习笔记

线程池

目录

在这里插入图片描述

package com.tfxing;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test01_ThreadPool {
    public static void main(String[] args) {
        //1、创建固定数量线程的线程池    适用于执行长期任务,性能好
//        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        //2、创建单个数量线程的线程池    任何时候都只有一个线程再执行,能保证任务的有序性
//        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //3、可扩展线程的线程池   适用于短时异步任务
        ExecutorService threadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            int count = i;
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"\t号银行柜台为"+count+"位客户服务");
            });
        }
        threadPool.shutdown();
    }
}

使用ThreadPoolExecutor创建线程池:

@Configuration
public class ThreadPoolConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(){
        return new ThreadPoolExecutor(50,100,3, TimeUnit.SECONDS,
        new ArrayBlockingQueue<>(10000));
    }
}

ThreadPoolExecutor源码:

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;
    }

1、ThreadPoolExecutor的七个参数:

     
        ThreadPoolExecutor的七个参数:
          corePoolSize:线程池中的常驻核心线程数
          maximumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于1
          keepAliveTime:多余的空闲线程的存活时间,当前池中线程数量超过corePoolSize时,
                        闲时间达到keepAliveTime时,
                        多余线程会被销毁直到只剩下corePoolSize个线程为止
          unit:keepAliveTime的单位(例如:TimeUnit.SECONDS)秒
          workQueue:任务队列,被提交单未被执行的任务
          threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认的即可
          handler: 拒绝策略,表示队列满了,并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时,
                   如何来拒绝请求执行的runnable的策略
                   
        
           

2、线程池的底层工作原理:

1、在创建了线程池后,开始等待请求

2、当调用了execute()方法添加一个请求任务时,线程池会做出如下判断:

2.1 、如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务

2.2、如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列

2.3、如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心数线程来立刻运行这个任务

2.4、如果队列满了,且正在运行的线程数量大于等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。

3、当一个线程完成任务时,它会从队列中取下一个任务来执行

4、当一个线程无事可做超过一定时间(keepAliveTime)时,线程会进行判断:

4.1、如果当前运行的线程数大于corePoolSize,那么这个线程会被停掉

4.2、所有线程池的所有任务完成后,它最终会收缩到corePoolSize的大小

线程进来后,如果corePoolSize已经满了,那么到workQueue中等待,如果再有线程进来,此时corePoolSize
和workQueue都满了,那么将线程数扩大到maximumPoolSize个(corePoolSize和扩容数的总和为maximumPoolSize)
,如果这时还有线程进入,此时maximumPoolSize和workQueue都满了,这时使用拒绝策略。当线程执行完毕后
如果扩容线程在keepAliveTime时间内没有线程进入,会将刚才的扩容线程关闭。 

在这里插入图片描述

3、面试题(为什么不用jdk提供的线程Execuetor)

Executors返回的线程池对象的弊端:
1、FixedThreadPool和SingleThreadPool:允许请求队列的长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致oom(out of memory)内存溢出

2、CacheThreadPool和ScheduledThreadPool:允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致oom(out of memory)内存溢出

4、线程池的拒绝策略

4.1、AbortPolicy(默认):直接抛出RejectedExecutionException异常组织系统正常运行

4.2、CallerRunsPolicy:“调用者运行”,一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量

4.3、DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交到当前任务

4.4、DiscardPolicy:该策略默默的抛弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略

4.2、测试代码

maximumPoolSize = Runtime.getRuntime().availableProcessors() + 1 //系统核数加1或2

import java.util.concurrent.*;

public class ExectorTest {
    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(2,
                5,//Runtime.getRuntime().availableProcessors() + 1 //系统核数加1或2
                3,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(5),//等待队列
                Executors.defaultThreadFactory(),//线程工厂
                new ThreadPoolExecutor.DiscardPolicy());//DiscardOldestPolicy());//CallerRunsPolicy());返回上一级//AbortPolicy());//拒绝策略,这里时默认的拒绝策略,直接报异常

        for (int i = 0; i < 20; i++) {
            int finalI = i;
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+":"+ finalI);
            });
        }
    }
}

5、Stream四大函数接口

在这里插入图片描述

Function:函数型接口
Function<String,Integer> function = s -> s.length();

System.out.println(function.apply("string"));  // 6
Predicate:断定型接口
Predicate<String> predicate = s -> s.length()>0;

System.out.println(predicate.test("hello"));  // true
Consumer:消费型接口
Consumer<String> consumer = s -> System.out.println(s);

consumer.accept("hello world");// hello world
Supplier:供给型接口
Supplier<String> supplier = ()-> "hello world";

System.out.println(supplier.get());// hello world

6、Stream流式计算

filter:需要传Predicate断定型接口
List<Integer> list = Arrays.asList(1,2,4,3,8,5);

list.stream().filter(l -> l % 2 == 0).filter(l -> l > 4).forEach(x-> System.out.println(x));
map:需要传Function函数型接口
 List<Integer> list = Arrays.asList(1,2,4,3,8,5);
        list.stream().filter(l -> l % 2 == 0).filter(l -> l > 4)
         .map(n -> n + 1).forEach(x-> System.out.println(x));
Collect(Collectors.toList):转换成一个List并返回
List<Integer> list2 = Arrays.asList(1,24,5,6,2,5);
        
list2.stream().map(num -> num * 2).collect(Collectors.toList())
        .forEach(num -> System.out.println(num));
Sorted:需要传入Compare接口

7、ForkJoin

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

class MyTask extends RecursiveTask<Integer>{
    private static final Integer ADJUST_VALUE = 10;
    private int begin;
    private int end;
    private int result;

    public MyTask(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if((end - begin)<=ADJUST_VALUE){
           for(int i =begin;i <= end;i++){
                result = result + i;
           }
        }else{
            int middle = (begin + end)/2;
            MyTask task01 = new MyTask(begin,middle);
            MyTask task02 = new MyTask(middle+1,end);
            task01.fork();
            task02.fork();
            result =  task01.join() + task02.join();
        }

        return result;
    }
}


/**
 * 分支合并例子
 * ForkJoinPool
 * ForkJoinTask
 * RecursiveTask
 */
public class ForkJoinDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        MyTask myTask = new MyTask(0,100);
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask);

        System.out.println(forkJoinTask.get());

        forkJoinPool.shutdown();
    }
}
 

8、CompletableFutrue

import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) {
        //runAsync:没有返回值
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
            System.out.println("没有返回值");
        });
        //supplyAsync:异步调用,有返回值
        CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("有返回值");
            return 1024;
        });
        integerCompletableFuture.whenComplete((t,u)->{//正常情况
            System.out.println("tttt:"+t);
            System.out.println("uuuu:"+u);
        }).exceptionally(f->{//异常情况
            System.out.println("excption:"+f.getMessage());
            return 404;
        });
    }
}

异步编排(组合式编程)

CompletableFuture<T>

线程的独立创建:

  有返回值线程:supply

  无返回值线程:run

线程的依赖创建:

  有返回值:apply

  无返回值:accept

同步或异步

  异步执行:async

  同步执行:sync

线程执行的组合:

  AllOf(a,b,c):用来阻塞主线程的执行,必须所有线程都执行完成,才能返回结果

  anyOf(a,b,c):只有某一个线程执行完毕就返回,不影响其他线程

  exceptionally():线程执行出现异常时调用

  whenComplate():线程执行完毕后调用

  

9、Callable

9.1、Callable接口和Runnable接口之间的区别(三种不同)

callable有泛型

1、callable的实现方法是call方法,runnable的实现方法是run方法,

2、call方法可以抛出异常,run方法不能抛出异常

3、call方法有返回值,run方法没有返回值

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值