继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【九月打卡】第15天 线程池【治理线程的最大法宝】

王开琦
关注TA
已关注
手记 36
粉丝 6
获赞 11

课程名称:玩转Java并发工具,精通JUC,成为并发多面手
课程章节:第3章 线程池【治理线程的最大法宝】
课程讲师: 悟空

课程内容

fixedThreadPool

由于传进去的LinkedBlockingQueue是没有容量上限的,所以当请求越来越多,并且无法及时处理完毕的时候,也就是请求堆积的时候,会容易占用大量的内存,可能会导致OOM

public class Executors {
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads/*maximumPoolSize*/,
                0L/*既然不可能超过核心线程数,这个参数是没有意义的*/, TimeUnit.MILLISECONDS/*这个参数和keepAliveTime是绑定的*/,
                new LinkedBlockingQueue<Runnable>()/*无界队列,因为FixedThreadPool和SingleThreadExecutor线程数量是固定的,当任务多的时候不得不用一个无限多的队列帮助存储*/);
    }
}

fixedThreadPoolOOM异常示例

/**
 * 描述: 演示fixedThreadPool出错的情况
 */
public class FixedThreadPoolOOM {
    private static ExecutorService executorService = Executors.newFixedThreadPool(1);

    public static void main(String[] args) {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            executorService.execute(new SubThread());
        }
    }
}

class SubThread implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.util.concurrent.LinkedBlockingQueue.offer(LinkedBlockingQueue.java:416)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371)
	at com.wkq.threadpool.FixedThreadPoolOOM.main(FixedThreadPoolOOM.java:14)

singleThreadExecutor

  • 单线程的线程池:它只会用唯一的工作线程来执行任务
  • 它的原理和FixedTreadPool是一样的,但是此时的线程数量被设置为了1

singleThreadPool的原理和fixedThreadPool基本一样,只不过把线程数直接设置成了1,所以这也会导致同样的问题,也就是当请求堆积的时候,可能会占用大量的内存。

public class Executors {
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                        0L, TimeUnit.MILLISECONDS,
                        new LinkedBlockingQueue<Runnable>()));
    }
}

3.3、 cachedThreadPool

  • 可缓存线程池。
  • 特点:无界线程池,具有自动回收多余线程的功能。

源码注释:Threads that have not been used for sixty seconds are terminated and removed from the cache。
Cache指的是对线程的缓存,如果一段时间线程空闲,就回收

public class Executors {
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>()/*不需要队列存储任务,新的任务来了直接交给线程去执行,如果没有则创建非核心线程执行*/);
    }
}

这里的弊端在于第二个参数maximumPoolSize被设置为了Integer.MAX_VALUE,这可能会创建数量非常多的线程,甚至导致OOM。

scheduledThreadPool

  • 支持定时及周期性的执行任务,做一些跟时间相关,跟推迟相关的工作
  • 用来代替定时任务以及定时器都是可以的
public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService {
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0/*它的任务是周期性的,所以不需要保留额外的线程,为0可以快速回收*/, NANOSECONDS,
                new DelayedWorkQueue()/*使用延迟队列,延迟队列的能力就是把它里面的任务根据时间先后去做延迟*/);
    }
}

示例:

public class ScheduledThreadPool {
    public static void main(String[] args) {
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10);
        threadPool.schedule(new Task(), 5/*延迟时间*/, TimeUnit.SECONDS/*延迟时间的单位*/);//定时
        threadPool.scheduleAtFixedRate(new Task(), 1/*第一次执行时间*/, 3/*以后每次执行的时间间隔*/, TimeUnit.SECONDS/*单位*/);//周期性
    }
}

以上四种线程池的构造函数的参数

Parameter FixedThreadPool CachedThreadPool ScheduledThreadPool SingleThreadPool
corePoolSize constructor-arg 0 constructor-arg 1
maxPoolSize same as corePoolSize INTEGER.MAX_VALUE INTEGER.MAX_VALUE 1
keepAliveTime 0 60s 0 0
workQueue LinkedBlocking SynchronousQueue DelayedWorkQueue LinkedBlocking

学习收获

今天学习了常见的几种线程池的使用场景和用法,收获颇丰!
图片描述

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP