java 高并发 之 线程池(Executor)

为什么需要线程池?

(1)因为服务器如果每一个请求都会创建一个新线程,会导致性能上的瓶颈,因为线程创建和销毁都需要jvm不停的处理,如果一个线程执行的时间 < (线程创建时间+线程销毁的时间)的时候,我们就要考虑线程的复用了!

(2)、线程数量创建过多,没有有效的管理,反而起到的是副作用,会大大降低系统的性能的!

(3)、我们要根据具体的业务需求不同,结合操作系统的处理器CPU核数,能够合理的控制线程池大小!选择不同策略的线程池,盲目使用也会带来一定风险,比如内存泄漏,死锁,并发问题…

使用线程池的好处

(1)、降低资源消耗:线程复用。

(2)、提高响应速度:有任务的时候,不需要去等待创建线程,直接使用已有的线程;

(3)、管理:线程池对线程进行统一分配,调优,监控等等;

Executor接口

Executor的UML图:(常用的几个接口和子类)
Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),
ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法
AbstractExecutorService:ExecutorService执行方法的默认实现
ScheduledExecutorService:一个可定时调度任务的接口
ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池
ThreadPoolExecutor:线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象:


public ThreadPoolExecutor(int corePoolSize,  // 核心线程数,如果运行的线程少于corePoolSize,则创建新线程来执行新任务,即使线程池中的其他线程是空闲的
                          int maximumPoolSize,// 最大线程数,可允许创建的线程数,corePoolSize和maximumPoolSize设置的边界自动调整池大小:
                          // corePoolSize <运行的线程数< maximumPoolSize:仅当队列满时才创建新线程
// corePoolSize=运行的线程数= maximumPoolSize:创建固定大小的线程池
                          long keepAliveTime, // 如果线程数多于corePoolSize,则这些多余的线程的空闲时间超过keepAliveTime时将被终止
                          TimeUnit unit, // keepAliveTime参数的时间单位
                          BlockingQueue<Runnable> workQueue, // 保存任务的阻塞队列,与线程池的大小有关:
  // 当运行的线程数少于corePoolSize时,在有新任务时直接创建新线程来执行任务而无需再进队列
  // 当运行的线程数等于或多于corePoolSize,在有新任务添加时则选加入队列,不直接创建线程
  // 当队列满时,在有新任务时就创建新线程
                          ThreadFactory threadFactory, // 使用ThreadFactory创建新线程,默认使用defaultThreadFactory创建线程
                          RejectedExecutionHandler handler) //后两个参数为可选参数:定义处理被拒绝任务的策略,默认使用ThreadPoolExecutor.AbortPolicy,任务被拒绝时将抛出RejectExecutorException

Executors类

Java线程池的静态工厂类:Executors类,初始化4种类型的线程池:

newFixedThreadPool()

说明:初始化一个指定线程数的线程池,其中corePoolSize == maxiPoolSize,使用LinkedBlockingQuene作为阻塞队列
特点:即使当线程池没有可执行任务时,也不会释放线程。

		ExecutorService executorService = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();

newCachedThreadPool()

说明:初始化一个可以缓存线程的线程池,默认缓存60s,线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使用SynchronousQueue作为阻塞队列;
特点:在没有任务执行时,当线程的空闲时间超过keepAliveTime,会自动释放线程资源;当提交新任务时,如果没有空闲线程,则创建新线程执行任务,会导致一定的系统开销;

	ExecutorService executorService = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();

因此,使用时要注意控制并发的任务数,防止因创建大量的线程导致而降低性能。

newSingleThreadExecutor()

说明:初始化只有一个线程的线程池,内部使用LinkedBlockingQueue作为阻塞队列。
特点:如果该线程异常结束,会重新创建一个新的线程继续执行任务,唯一的线程可以保证所提交任务的顺序执行

		ExecutorService executorService = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    log.info("task:{}", index);
                }
            });
        }
        executorService.shutdown();

newScheduledThreadPool()

特定:初始化的线程池可以在指定的时间内周期性的执行所提交的任务,在实际的业务场景中可以使用该线程池定期的同步数据。除了newScheduledThreadPool的内部实现特殊一点之外,其它线程池内部都是基于ThreadPoolExecutor类(Executor的子类)实现的。

		ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);

        executorService.schedule(new Runnable() {
            @Override
            public void run() {
                log.warn("schedule run");
            }
        }, 3, TimeUnit.SECONDS);

        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                log.warn("schedule run");
            }
        }, 1, 3, TimeUnit.SECONDS);

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                log.warn("timer run");
            }
        }, new Date(), 5 * 1000);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章