JUC学习笔记-2 阻塞队列、线程池、四大函数式接口、stream流式计算、forkJoin、异步回调

阻塞队列 BlockingQueue

什么时候使用:多线程并发处理、线程池
四组API

方式 抛出异常 有返回值、不抛异常 阻塞 等待 超时等待
添加 add offer() put() offer(E e,long timeout,TimeUnit timeUnit)
移除 remove poll() take() poll(long timeout,TimeUnit timeUnit)
检查队首元素 element peek() - -
/**抛异常*/
    private static void test1() {
    /** 创建具有给定(固定)容量和默认访问策略的ArrayBlockingQueue。 */
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
        //存
        queue.add(1);
        System.out.println(queue.add(2)); //true
        queue.add(3);//抛异常
        //取
        System.out.println(queue.remove());
        System.out.println(queue.remove());
        System.out.println(queue.remove()); //抛异常
        //检查队首元素
        System.out.println(queue.element()); //抛异常:NoSuchElementException
    }
    /**有返回值,不抛异常*/
    private static void test2() {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
        queue.offer(1);
        System.out.println(queue.offer(2)); //打印 true
        System.out.println(queue.offer(3)); //打印 false
        System.out.println("--------");
        queue.poll();
        System.out.println(queue.poll()); //打印 结果2
        System.out.println(queue.poll());  //打印null
        System.out.println("--------");
        System.out.println(queue.peek());
    }
    /**阻塞等待*/
    private static void test3() throws InterruptedException {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
        queue.put(1);
        queue.put(2); // 返回值void
//        queue.put(3); //阻塞
        //取
        queue.take();
        System.out.println(queue.take()); //打印 结果2
        System.out.println(queue.take());  //阻塞
    }
    /**超时等待*/
    private static void test4() throws InterruptedException {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
        System.out.println(queue.offer(1)); //打印 true
        System.out.println(queue.offer(2)); //打印 true
        /**
         * 将指定的元素插入此队列,如果必要的话,等待指定的等待时间以使空间可用。
         * */
        System.out.println(queue.offer(3,2, TimeUnit.SECONDS)); //超时打印false
        System.out.println("--------");
        //取
        System.out.println(queue.poll());//打印 结果1
        System.out.println(queue.poll()); //打印 结果2
        /**
         * 检索并删除此队列的头,如果有必要使元素可用,则等待指定的等待时间。
         * */
        System.out.println(queue.poll(2,TimeUnit.SECONDS));  //超时打印null
    }
同步队列 SynchronousQueue?
线程池

三大方法、7大参数、4种拒绝策略(拒绝策略与阻塞队列4组API的关系)

推荐博客

  • 面试必备:Java线程池解析
  • 你真的懂ThreadPoolExecutor线程池技术吗?看了源码你会有全新的认识

线程池的好处

  • 降低资源消耗
  • 提高相应速度
  • 方便线程管理
    JUC学习笔记-2 阻塞队列、线程池、四大函数式接口、stream流式计算、forkJoin、异步回调_第1张图片

三大方法

Executors.newSingleThreadExecutor();//单个线程
Executors.newFixedThreadPool(5);//创建固定的线程池大小
Executors.newCachedThreadPool();// 可扩展线程池

七大参数

  1. int corePoolSize:线程池核心线程数最大值
  2. int maximumPoolSize:线程池最大线程数大小
  3. long keepAliveTime:线程池中非核心线程空闲的存活时间大小
  4. TimeUnit unit:线程空闲存活时间单位
  5. BlockingQueue workQueue:存放任务的阻塞队列
  6. ThreadFactory threadFactory:用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题。
  7. RejectedExecutionHandler handler :线城池的饱和策略事件,主要有四种类型

手动创建线程池

public static void main(String[] args) {
        //自定义线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1,
                3,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(2),
                Executors.defaultThreadFactory(),
//                new ThreadPoolExecutor.CallerRunsPolicy() 
//                new ThreadPoolExecutor.AbortPolicy() 
//                new ThreadPoolExecutor.DiscardPolicy()
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        try {
            for (int i = 1; i <= 8; i++) {
                /*if (i==6){
                    TimeUnit.SECONDS.sleep(3);
                }*/
                final int temp = i;
                //使用线程池来创建线程
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName()+" √√√√√√√ "+temp+"线程开始");
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" ××××××××"+temp+" 线程结束");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }

四种拒绝策略

  • AbortPolicy(中止策略):丢弃任务并抛出RejectedExecutionException异常。
  • DiscardPolicy(丢弃策略):丢弃任务,但是不抛出异常。
  • DiscardOldestPolicy(弃老策略):丢弃队列最前面的任务,然后重新提交被拒绝的任务
  • CallerRunsPolicy(调用者运行策略):由调用线程(提交任务的线程)处理该任务

注:

  1. 策略详细介绍及其他第三方策略参考 八种拒绝策略浅析
  2. 细节详见源码 ,可参考ThreadPoolExecutor源码解析

线程池的默认拒绝策略为AbortPolicy

/**
     * The default rejected execution handler
     */
    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();

最大线程如何定义

  1. CPU密集型,通过 Runtime.getRuntime().availableProcessors()获取cpu核数,即为最大线程数
  2. IO密集型 > 你程序中十分耗IO的线程
    JUC学习笔记-2 阻塞队列、线程池、四大函数式接口、stream流式计算、forkJoin、异步回调_第2张图片
    参考:到底如何设置 Java 线程池的大小?

四大函数式接口(必须掌握)

Function()、Predicate(断言型接口)、Consumer(消费型接口,只有输入没有返回值)、Supplier(供给型接口)

Stream流式计算

题目要求:一分钟内完成此题,只能用一行代码实现!
现在有5个用户!筛选:
1、ID必须是偶数
2、年龄必须大于23岁
3、用户名转为大写字母
4、用户名字母倒着排序
5、只输出一个用户!

public class StreamDemo {
    public static void main(String[] args) {
        User u1 = new User(1, "a", 21);
        User u2 = new User(2, "b", 22);
        User u3 = new User(3, "c", 23);
        User u4 = new User(4, "d", 24);
        User u5 = new User(5, "e", 25);
        User u6 = new User(6, "f", 26);
        User u8 = new User(8, "h", 28);
        List<User> list = Arrays.asList(u1, u2, u3, u4, u5,u6,u8);
        // lambda表达式、链式编程、函数式接口、Stream流式计算
        list.stream()
                .filter(user -> user.getId()%2==0)
                .filter(user -> user.getAge()>23)
                .map(user -> {
                    user.setName(user.getName().toUpperCase());
                    return user;
                })  //map可以转换
                .sorted((o1, o2) -> o2.getName().charAt(0)-o1.getName().charAt(0))
                .limit(1)
                .forEach(System.out::println);
    }
}
//省略User类
ForkJoin(分支合并)

ForkJoin在JDK1.7出现,作用:并行执行任务、提高效率。大量数据
并行流 IntStream parallel()

异步回调

CompletableFuture

你可能感兴趣的:(java学习,java,多线程)