JUC进阶2---线程池和函数式接口

1、线程池

线程池:3大方法、7大参数、4种拒绝策略

线程池的好处
1、降低资源的消耗
2、提高响应的速度
3、方便管理。
线程复用、可以控制最大并发数、管理线程

1.1、3大方法

public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();  //单个线程
        ExecutorService threadPool = Executors.newFixedThreadPool(5);  //固定线程池大小
        ExecutorService threadPool = Executors.newCachedThreadPool();  // 可伸缩,遇强则强

        try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "执行了");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }

    }
}

1.2、7大参数

源码分析:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
// 都是调用的 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;
}

JUC进阶2---线程池和函数式接口_第1张图片

1.3、4种拒绝策略

JUC进阶2---线程池和函数式接口_第2张图片

ThreadPoolExecutor.AbortPolicy()  // 队列满了之后就不处理,抛出异常
ThreadPoolExecutor.CallerRunsPolicy()  // 哪里来去哪里

JUC进阶2---线程池和函数式接口_第3张图片

ThreadPoolExecutor.DiscardPolicy()  //队列满了就丢弃任务
ThreadPoolExecutor.DiscardOldestPolicy()  //队列满了就去和最早的竞争,不会抛出异常

1.4、小结和拓展

最大的线程数应该如何设置?maximumPoolSize

  1. CUP密集型:根据CPU的核数去设置,保持CPU的效率最高
  2. IO密集型:根据程序中十分耗IO的线程的个数,io十分占用资源,大于,最好是两倍个数
// 获取CPU的核数
int processors = Runtime.getRuntime().availableProcessors();

2、四大函数式接口

新时代的程序员:lambda表达式、链式编程、函数式接口、Stream流式计算

2.1、Function 功能型接口

  • Function 函数型接口, 有一个输入参数,有一个输出

JUC进阶2---线程池和函数式接口_第4张图片

public class FunctionDemo {
    public static void main(String[] args) {
        /*Function function = new Function() {
            @Override
            public String apply(String str) {
                return str;
            }
        };*/
        Function function = (str) -> {
            return str;
        };
        System.out.println(function.apply("hello"));
    }
}

2.2、Predicate 断定型接口

  • 断定型接口:有一个输入参数,返回值只能是 布尔值!
    JUC进阶2---线程池和函数式接口_第5张图片
public class PredicateDemo {
    public static void main(String[] args) {
        /*Predicate predicate = new Predicate() {
            @Override
            public boolean test(String str) {
                return str.isEmpty();
            }
        };*/
        Predicate<String> predicate = (str) -> {return str.isEmpty();};
        System.out.println(predicate.test("hello"));
    }
}

2.3、Consumer 消费型接口

  • 消费型接口: 只有输入,没有返回值
    JUC进阶2---线程池和函数式接口_第6张图片
public class ConsumerDemo {
    public static void main(String[] args) {
        /*Consumer consumer = new Consumer() {
            @Override
            public void accept(String s) {
                System.out.println("消费了" + s);
            }
        };*/
        Consumer<String> consumer = (str) -> {
            System.out.println("消费了" + str);
        };
        consumer.accept("美食");
    }
}

2.4、Supplier 供给型接口

  • 供给型接口 没有参数,只有返回值
    JUC进阶2---线程池和函数式接口_第7张图片
public class SupplierDemo {
    public static void main(String[] args) {
        /*Supplier supplier = new Supplier() {
            @Override
            public Integer get() {
                System.out.println("调用了get方法");
                return 1024;
            }
        };*/
        Supplier<Integer> supplier = () -> {return 1024;};
        System.out.println(supplier.get());
    }
}

3、Stream 流式计算

  • lambda表达式、链式编程、函数式接口、Stream流式计算 一起使用
@Data
@NoArgsConstructor
@AllArgsConstructor
class User {
    private Integer id;
    private String name;
    private Integer age;
}
/**
 * 题目要求:一分钟内完成此题,只能用一行代码实现!
 * 现在有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(6,"e",25);
        // 集合就是存储
        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
        // 计算交给Stream流
        list.stream()
                .filter(user -> user.getId()%2 == 0)
                .filter(user -> user.getAge() > 23)
                .map(user -> {
                    user.setName(user.getName().toUpperCase());
                    return user;
                })
                .sorted((user1, user2) -> {
                    return user2.getName().compareTo(user1.getName());
                })
                .limit(1)
                .forEach(System.out::println);  // User(id=6, name=E, age=25)
    }
}

4、ForkJoin

ForkJoin 在 JDK 1.7 , 并行执行任务!提高效率。大数据量!
JUC进阶2---线程池和函数式接口_第8张图片

ForkJoin 特点:工作窃取,每一个线程的任务都是一个双端队列,当一个线程完成任务之后,可以争抢别人的任务来执行。

public class ForkJoinDemo extends RecursiveTask<Long> {
    private Long start;
    private Long end;
    private Long temp = 10000L;  // 临界值
    public ForkJoinDemo(Long start, Long end) {
        this.start = start;
        this.end = end;
    }
    @Override
    protected Long compute() {
        if ((end - start) < temp) {
            Long sum = 0L;
            for (Long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        } else {
            long middle = (start + end) / 2;
            ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
            task1.fork();
            ForkJoinDemo task2 = new ForkJoinDemo(middle, end);
            task2.fork();
            return task1.join() + task2.join();
        }
    }
}
  • 测试
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        test1();  //2033 ms
//        test2();  //1229 ms
//        test3();  //121 ms
    }

    // Stream并行流
    public static void test3() {
        long start = System.currentTimeMillis();
        long sum = LongStream.rangeClosed(0L, 10000_0000L).parallel().reduce(0, Long::sum);
        long end = System.currentTimeMillis();
        System.out.println("sum="+"时间:"+(end-start));
    }
    // ForkJoin
    public static void test2() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoinDemo(0L, 10000_0000L);
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);
        Long sum = submit.get();
        long end = System.currentTimeMillis();
        System.out.println("sum="+sum+" 时间:"+(end-start));
    }
    //普通方法
    public static void test1() {
        Long sum = 0L;
        long start = System.currentTimeMillis();
        for (Long i = 1L; i <= 10000_0000; i++) {
            sum += i;
        }
        long end = System.currentTimeMillis();
        System.out.println("sum="+sum+" 时间:"+(end-start));
    }
}

5、Future 异步回调

public class FutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 没有返回值的 runAsync 异步回调
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行了异步任务");
        });
        System.out.println("执行了main函数方法");
        completableFuture.get();  //阻塞,获取执行结果
    }
}
public class FutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 有返回值的 supplyAsync 异步回调
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "执行了有返回值的异步回调");
            int i = 1 / 0;
            return 200;
        });
        System.out.println(completableFuture.whenComplete((t, u) -> {
            System.out.println("t=" + t);  // 返回正常结果
            System.out.println("u=" + u);  // 返回错误信息 u=java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
        }).exceptionally((e) -> {
            System.out.println(e.getMessage());
            return 404;  // 可以获得错误的返回结果
                }).get()
        );
    }
}

JUC进阶2---线程池和函数式接口_第9张图片

你可能感兴趣的:(JUC学习笔记,juc,线程池,函数式编程,lambda)