java线程池

Posted award

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java线程池相关的知识,希望对你有一定的参考价值。

线程池:

  简单理解,就是一个管理线程的池子。

  • 它帮我们管理线程,避免增加创建线程和销毁线程的资源消耗。因为线程其实也是一个对象,创建一个对象,需要经过类加载过程,销毁一个对象,需要走GC垃圾回收流程,都是需要资源开销的。
  • 提高响应速度。如果任务达到了,相对于从线程池拿线程,重新去创建一条线程执行,速度要慢很多。
  • 重复利用。线程使用完,再放回线程池,可以达到重复利用的效果,节省资源。

线程池的创建:

  线程池可以通过ThreadpoolExecutor来创建:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) 
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    

  几个核心参数的作用:

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

任务执行:

  • 提交一个任务,线程池里存活的核心线程数小于线程数corePoolSize时,线程池会创建一个核心线程去处理提交的任务。
  • 如果线程核心线程数已满,线程数已经等于corePoolSize,一个新提交的任务,会被放进任务队列workQueue排队等待执行。
  • 当线程池里面已经存活的线程数已经等于corePoolSize,并且任务队列workQueue也满,判断线程数是否已满,如果没有,创建一个非核心线程执行提交的任务。、
  • 如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。

四种拒绝策略:

  • AbortPolicy(抛出一个异常,默认的)
  • DiscardPolicy(直接丢弃任务)
  • DiscaOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)
  • callerRunsPolicy(交给线程池调用所在的线程进行处理)

线程池异常处理:

  在使用线程池处理任务的时候,任务代码可能抛出RuntimeException,抛出异常后,线程池可能捕获它,也可能创建一个新的线程来代替异常的线程,我们可能无法感知任务出现了异常,因此我们需要考虑线程池异常情况。

       ExecutorService executorService=Executors.newFixedThreadPool(6);
        for (int i = 0; i < 6; i++) 
            executorService.submit(()->
                System.out.println("current thread name"+Thread.currentThread().getName());
                try 
                    Object object=null;
                    System.out.println("result"+object.toString());
                catch (Exception e)
                    System.out.println("program occur"+e);
                
            );
            

看下源码:

    /**
     * @throws RejectedExecutionException @inheritDoc
     * @throws NullPointerException       @inheritDoc
     */
    public Future<?> submit(Runnable task) 
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    

    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) 
        return new FutureTask<T>(runnable, value);
    

    public FutureTask(Runnable runnable, V result) 
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    

    public static <T> Callable<T> callable(Runnable task, T result) 
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
     
    public void execute(Runnable command) 
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) 
            if (addWorker(command, true))
                return;
            c = ctl.get();
        
        if (isRunning(c) && workQueue.offer(command)) 
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        
        else if (!addWorker(command, false))
            reject(command);
    
    public void run() 
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try 
            Callable<V> c = callable;
            if (c != null && state == NEW) 
                V result;
                boolean ran;
                try 
                    result = c.call();
                    ran = true;
                 catch (Throwable ex) 
                    result = null;
                    ran = false;
                    setException(ex);
                
                if (ran)
                    set(result);
            
         finally 
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        
    

通过以上分析,submit执行的任务,可以通过Future对象的get()方法接收抛出的异常,再进行处理。因此可以通过future.get()来对异常进行处理。

    public static void main(String[] args) 
        ExecutorService executorService = Executors.newFixedThreadPool(6);
        for (int i = 0; i < 6; i++) 
            Future future = executorService.submit(() -> 
                System.out.println("current thread name" + Thread.currentThread().getName());
                Object object = null;
                System.out.println("result" + object.toString());
            );
            try 
                future.get();
             catch (Exception e) 
                System.out.println("program occur" + e);
            
        
    

因此可以处理异常:

  1. 在任务代码try/catch进行异常捕获。

  2. 通过Future对象的get方法抛出异常,再进行捕获。

  3. 为工作者线程设置UncaughtExceptionHandler,在方法中处理异常。

    public static void main(String[] args) 
        ExecutorService executorService = Executors.newFixedThreadPool(6, t -> 
            Thread thread = new Thread(t);
            thread.setUncaughtExceptionHandler((thread1, e) -> 
                System.out.println(thread1.getName() + " occur:" + e);
            );
            return thread;
        );
        for (int i = 0; i < 8; i++) 
            executorService.execute(() -> 
                Object object = null;
                System.out.println("result" + object.toString());
            );
        
    

以上是关于java线程池的主要内容,如果未能解决你的问题,请参考以下文章

Java线程池

java创建线程池都有哪些

java线程池

java线程池原理

JAVA线程池使用哪一种比较好

如何使用java语言实现一个线程池,不使用jdk自带的线程池