多线程与高并发(七):详解线程池 - 自定义线程池,JDK自带线程池,ForkJoin,源码解析等

Executor 接口关系

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

Callable:类似于Runnable,但是可以有返回值

Future:存储将来执行的结果。Callable被执行完之后的结果,被封装到Future里面。

Future 示例:

/**
 * 认识Callable,对Runnable进行了扩展
 * 对Callable的调用,可以有返回值
 */
package com.mashibing.juc.c_026_01_ThreadPool;

import java.util.concurrent.*;

public class T03_Callable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> c = new Callable() {
            @Override
            public String call() throws Exception {
                return "Hello Callable";
            }
        };

        ExecutorService service = Executors.newCachedThreadPool();
        Future<String> future = service.submit(c); //异步

        System.out.println(future.get());//阻塞
        service.shutdown();
    }
}

FutureTask:更加灵活,是Runnable和Future的结合,既是一个Runnable,又可以存结果

FutureTask示例:

/**
 * 认识FutureTask
 */
package com.mashibing.juc.c_026_01_ThreadPool;

import java.util.concurrent.*;

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

        FutureTask<Integer> task = new FutureTask<>(() -> {
            TimeUnit.MILLISECONDS.sleep(500);
            return 1000;
        }); //new Callable () { Integer call();}

        new Thread(task).start();
        System.out.println(task.get()); //阻塞
    }
}

CompletableFuture
可以用来管理多个Future的结果,对各种各样的结果进行组合处理。你可以去查查它的API~
提供了很多非常好用的接口,十分友好!

示例:假设你能够提供一个服务,这个服务查询各大电商网站同一类产品的价格并汇总展示,你用CompletableFuture开启三个线程来完成这个任务

package com.mashibing.juc.c_026_01_ThreadPool;

import java.io.IOException;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class T06_01_CompletableFuture {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long start, end;

        /*start = System.currentTimeMillis();

        priceOfTM();
        priceOfTB();
        priceOfJD();

        end = System.currentTimeMillis();
        System.out.println("use serial method call! " + (end - start));*/

        start = System.currentTimeMillis();

        CompletableFuture<Double> futureTM = CompletableFuture.supplyAsync(() -> priceOfTM());
        CompletableFuture<Double> futureTB = CompletableFuture.supplyAsync(() -> priceOfTB());
        CompletableFuture<Double> futureJD = CompletableFuture.supplyAsync(() -> priceOfJD());

        CompletableFuture.allOf(futureTM, futureTB, futureJD).join(); // 提供对于一堆任务的管理:这三个任务全部完成之后,才能继续向下运行
//        CompletableFuture.anyOf(futureTM, futureTB, futureJD).join();  // 任意一个任务完成,就能继续向下运行

        CompletableFuture.supplyAsync(() -> priceOfTM())
                .thenApply(String::valueOf)
                .thenApply(str -> "price " + str)
                .thenAccept(System.out::println);


        end = System.currentTimeMillis();
        System.out.println("use completable future! " + (end - start));

        try {
            System.in.read();//因为里面全是异步,所以需要阻塞一下,才能正常的等待它们输出,不然主线程先结束了。。
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static double priceOfTM() {
        delay();
        return 1.00;
    }

    private static double priceOfTB() {
        delay();
        return 2.00;
    }

    private static double priceOfJD() {
        delay();
        return 3.00;
    }

    /*private static double priceOfAmazon() {
        delay();
        throw new RuntimeException("product not exist!");
    }*/

    private static void delay() {
        int time = new Random().nextInt(500);
        try {
            TimeUnit.MILLISECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("After random %s sleep!\n", time);
    }
}

线程池

ThreadPoolExecutor:我们通常所说的线程池
ForkJoinPoll:先将任务分解,最后再汇总
在这里插入图片描述

如何自定义一个线程池

阿里《Java开发手册》建议自定义线程池,所以我们先来看看如何自定义一个线程池。

在这里插入图片描述

线程池
维护两个集合:

  • 线程集合
  • 任务集合

用的是HashSet
在这里插入图片描述

在这里插入图片描述
定义一个自定义线程池,最多有7个参数,这个面试经常被使劲问

在这里插入图片描述

package com.mashibing.juc.c_026_01_ThreadPool;

import java.io.IOException;
import java.util.concurrent.*;

public class T05_00_HelloThreadPool {

    static class Task implements Runnable {
        private int i;

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

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + " Task " + i);
            try {
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public String toString() {
            return "Task{" +
                    "i=" + i +
                    '}';
        }
    }

    public static void main(String[] args) {
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 4,
                60, TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(4),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        for (int i = 0; i < 8; i++) {
            tpe.execute(new Task(i));
        }

        System.out.println(tpe.getQueue());

        tpe.execute(new Task(100));

        System.out.println(tpe.getQueue());

        tpe.shutdown();
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章