美文网首页
JAVA并发(10)——线程池

JAVA并发(10)——线程池

作者: alexwu59 | 来源:发表于2018-07-02 15:44 被阅读0次

    线程池的有点

    1.降低资源的消耗:系统每创建一个线程都是资源消耗的,如果业务并发量很大,而且每个任务处理速度快,频繁创建线程会引起系统性能下降,避免由于线程创建数量巨大,引起系统资源不足导致内存溢出。
    2.提高响应速度:当有新任务来的时候,不需要创建线程,而直接使用线程池中的线程。

    线程池的使用

    Executor:是一个接口,只有一个方法execute,ExecutorService接口继承了Executor,并且提供了其他一些线程池方法。AbstractExecutorService是ExecutorService默认实现类,提供了部分方法的默认实现,ThreadPoolExceutor就是线程池的实现类,他继承了AbstractExecutorService类,对其进行了扩展,但是在使用的java线程池的时候,通常不直接使用ThreadPoolExceutor去创建java线程池。通常使用Executors工厂类,创建不同的线程池对象,一般有4种:
    1.固定大小线程池 2带缓冲功能的线程池对象 3只有一个线程的线程池对象 4执行定时任务的线程池
    期中前三个方法都是都通过 new ThreadPoolExceutor,创建对象的时候,传入不同的参数来实现的。

    ThreadPoolExceutor的构造方法一般有以下几个参数:
    corePoolSize:线程池的核心线程数,当一个任务被添加到线程池的时候,判断线程池中的线程数是不是等于corePoolSize,如果等于,那么新来的任务会放入到阻塞队列中,等待被执行。
    maximumPoolSize:当线程池中的阻塞队列已经满了,又有新任务添加到线程池中的时候,如果当前线程池中的线程数,小于maximumPoolSize,那么线程池会创建新的线程去执行任务。
    keepAliveTime:当前线程没有执行任务,继续存活的时候,如果当前线程池中的数目大corePoolSize,多出的线程会被停掉
    workQueue:阻塞队列的实现方法
    handler:线程池的饱和策略

    ThreadPoolExceutor执行线程任务分为两种方式:exceute和sumbit,分别调用这两个方法:

    submit方法的返回是个Future类型的对象,通过该对象的get方法可以获取submit提交线程执行后的结果,而且还可以捕捉到线程执行的异常。
    submit的方法中把 callable对象或者runable对象包装成一个FutureTask的对象:

    RunnableFuture<T> ftask = newTaskFor(task);

    下面是newTaskFor的实现方法创建一个FutureTask对象 然后去调用ThreadPoolExecutor的execute方法。
    1.判断当前线程池线程数量小于corePoolSize,创建新线程。
    2.如果数量大于等于coresize,线程池属于运行状态且加入阻塞队列,如果成功执行3,否则执行4
    3.重新检查线程池运行状态,如果线程池没有RUNNING,且成功从阻塞队列中删除任务,则执行reject方法处理任务;
    4.如果线程池不是RUNNING状态或者加入阻塞队列失败,则尝试创建新线程直到maxPoolSize,如果失败,则调用reject()方法运行相应的拒绝策略。
      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);
        }
    

    addWorker方法是完成创建线程池线程的功能,下面介绍一下addWorker的实现:

    boolean addWorker(Runnable firstTask, boolean core) 
    

    addWorker两个参数,第一个表示任务,第二个表示是启动core核心线程还是maximumPoolSize线程。
    addWorker主要是将来的线程任务firstTask包装成一个Work对象:w,work是一个runnable接口的实现,然后通过w对象获取当前线程t,然后启动t线程,t线程就是w对象自己的线程。
    t线程执行的内容是:
    runWorker(this)方法:该this代表w对象自己,runWorker方法内就是执行firstTask的任务:



    入上图所示:task.run()方法会执行上面中的ftask对象的run方法:



    由于ftask对象是FutureTask类的对象,因此task.run(),调用的是就是FutureTask的run方法:
    因为这里run方法会执行call方法,在执行call可以保持返回值和获取异常信息,因此在get的时候,就能获取到方法的返回值和捕捉到异常信息。

    相关文章

      网友评论

          本文标题:JAVA并发(10)——线程池

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