Java并发 -- 线程池

作者: 编程小世界 | 来源:发表于2019-05-22 21:41 被阅读1次

    创建线程

    创建普通对象,只是在JVM的堆里分配一块内存而已

    创建线程,需要调用操作系统内核的API,然后操作系统需要为线程分配一系列资源,成本很高

    线程是一个重量级对象,应该避免频繁创建和销毁,采用线程池方案

    一般的池化资源

    // 假设Java线程池采用一般意义上池化资源的设计方法

    class ThreadPool {

        // 获取空闲线程

        Thread acquire() {

        }

        // 释放线程

        void release(Thread t) {

        }

    }

    // 期望的使用

    ThreadPool pool;

    Thread T1 = pool.acquire();

    // 传入Runnable对象

    T1.execute(() -> {

        // 具体业务逻辑

    });

    生产者-消费者模式

    业界线程池的设计,普遍采用生产者-消费者模式,线程池的使用方是生产者,线程池本身是消费者

    public class MyThreadPool {

        // 工作线程负责消费任务并执行任务

        class WorkerThread extends Thread {

            @Override

            public void run() {

                // 循环取任务并执行

                while (true) {

                    Runnable task = null;

                    try {

                        task = workQueue.take();

                    } catch (InterruptedException e) {

                    }

                    task.run();

                }

            }

        }

        // 利用阻塞队列实现生产者-消费者模式

        private BlockingQueue<Runnable> workQueue;

        // 内部保存工作线程

        List<WorkerThread> threads = new ArrayList<>();

        public MyThreadPool(int poolSize, BlockingQueue<Runnable> workQueue) {

            this.workQueue = workQueue;

            for (int i = 0; i < poolSize; i++) {

                WorkerThread work = new WorkerThread();

                work.start();

                threads.add(work);

            }

        }

        // 提交任务

        public void execute(Runnable command) throws InterruptedException {

            workQueue.put(command);

        }

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

            // 创建有界阻塞队列

            BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(2);

            // 创建线程池

            MyThreadPool pool = new MyThreadPool(10, workQueue);

            // 提交任务

            pool.execute(() -> {

                System.out.println("hello");

            });

        }

    }

    Java线程池ThreadPoolExecutor

    public ThreadPoolExecutor(int corePoolSize,

                              int maximumPoolSize,

                              long keepAliveTime,

                              TimeUnit unit,

                              BlockingQueue<Runnable> workQueue,

                              ThreadFactory threadFactory,

                              RejectedExecutionHandler handler)

    // 让所有线程都支持超时,如果线程池很闲,那么将撤销所有线程

    public void allowCoreThreadTimeOut(boolean value)

    corePoolSize:线程池保有的最小线程数

    maximumPoolSize:线程池创建的最大线程数

    keepAliveTime & unit

    如果一个线程空闲了keepAliveTime & unit,并且线程池的线程数大于corePoolSize,那么这个空闲的线程就要被回收

    workQueue:工作队列

    threadFactory:自定义如何创建线程

    handler

    线程池中的所有线程都很忙碌,并且工作队列也满了(工作队列是有界队列),此时提交任务,线程池会拒绝接收

    CallerRunsPolicy:提交任务的线程自己去执行该任务

    AbortPolicy:默认的拒绝策略,抛出RejectedExecutionException

    DiscardPolicy:直接丢弃任务,不会抛出任何异常

    DiscardOldestPolicy:丢弃最老的任务,然后把新任务加入到工作队列中

    Executors

    不建议使用Executors,因为Executors提供的很多默认方法使用的是无界队列LinkedBlockingQueue

    在高负载的情况下,无界队列容易导致OOM,而OOM会导致所有请求都无法处理

    因此强烈建议使用有界队列

    拒绝策略

    使用有界队列,当任务过多时,线程池会触发拒绝策略

    线程池默认的拒绝策略会抛出RejectedExecutionException,这是一个运行时异常,开发时很容易忽略

    如果线程池处理的任务非常重要,可以自定义拒绝策略

    异常处理

    使用ThreadPoolExecutor.execute()方法提交任务时,如果任务在执行过程中出现运行时异常

    会导致执行任务的线程终止,并且无法获得任何通知

    因此最稳妥的方法还是捕获所有异常并处理

    我自己是一个从事了6年的Java全栈工程师,最近整理了一套适合2019年学习的Java\大数据资料,从基础的Java、大数据面向对象到进阶的框架知识都有整理哦,可以来我的主页免费领取哦。

    try {

        // 业务逻辑

    } catch (RuntimeException x) {

        // 按需处理

    } catch (Throwable x) {

        // 按需处理

    }

    相关文章

      网友评论

        本文标题:Java并发 -- 线程池

        本文链接:https://www.haomeiwen.com/subject/ubalzqtx.html