多线程学习笔记7之线程池

Executors

创建线程池的类,提供四种线程池:

  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
    示例代码:
public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> c = () -> "Hello Callable";

        ExecutorService service = Executors.newCachedThreadPool();
        //异步
        Future<String> future = service.submit(c);
        //阻塞
        System.out.println(future.get());

        service.shutdown();
    }
}
  • newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
  • newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行
  • newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

Callable

Callable是一个任务,类似于Runnable,但是Callable任务是有返回值的,一般用线程池去执行这个Callable任务,返回一个包含Callable执行结果的Future,这个操作是异步的,然后通过Future.get()这个阻塞方法去获取执行结果

Future

存储执行任务产生的结果

FutureTask

代替Callable任务+Future,FutureTask实现了RunnableFuture接口,而RunnableFuture接口同时继承了Runnable和Future接口(接口可以同时继承2个以上接口),所以FutureTask本身就是一个任务和Future,简单使用如下

public class FutureTaskDemo {

    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的结果,简单使用如下

public class CompletableFutureDemo {
    public static void main(String[] args) {
        long start, end;

        start = System.currentTimeMillis();

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

        CompletableFuture.allOf(futureTM, futureTB, futureJD).join();

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

    }

    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 void delay() {
        int time = new Random().nextInt(500);
        try {
            TimeUnit.MILLISECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("After %s sleep!\n", time);
    }
}

ThreadPoolExecutor及七个参数

创建线程池构造方法7个参数,如下图

在这里插入图片描述

  • corePoolSize 线程池核心线程大小 处于空闲也不会被回收的线程
  • maximumPoolSize 线程池最大线程数量 达到空闲时间就会被回收的线程
  • keepAliveTime 空闲线程存活时间
  • unit 空间线程存活时间单位
  • workQueue 工作队列
    新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列:

①ArrayBlockingQueue

基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。

②LinkedBlockingQuene

基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。

扫描二维码关注公众号,回复: 8844963 查看本文章

③SynchronousQuene

一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。

④PriorityBlockingQueue

具有优先级的无界阻塞队列,优先级通过参数Comparator实现

  • threadFactory 线程工厂

创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等

  • handler 拒绝策略
    当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略:

①CallerRunsPolicy

该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。

②AbortPolicy

该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。

③DiscardPolicy

该策略下,直接丢弃任务,什么都不做。

④DiscardOldestPolicy

该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

简单使用代码如下:

public class ThreadPoolExecutorDemo {
    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<>(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();
    }
发布了21 篇原创文章 · 获赞 1 · 访问量 477

猜你喜欢

转载自blog.csdn.net/qq_24286273/article/details/104083748
今日推荐