Java并发 ---- 线程池

newThread的弊端

  (1)每次new Thread新建对象,性能较差
  (2)线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多的系统资源导致死机或者OOM
  (3)缺少更多得功能,如更多执行,定期执行,线程中断

线程池的好处

  (1)重用存在的线程,减少对象的创建,消亡的开销,性能好
  (2)可以有效控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞
  (3)提供定时执行,定期执行,单线程,并发数控制等功能

线程池 - ThreadPoolExecutor

一些重要参数,以及处理时的情况:
  1.corePoolSize : 核心线程数量。
  2.maximumPoolSize : 线程最大线程数。
  3.workQueue : 阻塞队列,储存等待执行的任务,很重要,会对线程池运行过程产生重大影响。

1.运行的线程数小于corePoolSize的时候,直接创建新线程来执行任务,即使其他线程池的其它线程是空闲的。
2.运行的线程数大于等于corePoolSize且小于maximumPoolSize时只有当workQueue满的时候才创建新的线程来执行任务。
3.如果设置的corePoolSize等于maximumPoolSize,则创建的线程池大小是固定的。
4.如果运行的线程数等于maximumPoolSize,且workQueue还没有满,则新任务会添加到workQueue中。
5.如果运行线程数等于maximumPoolSize,且workQueue已经满了,则通过拒绝策略的参数来处理这个任务。

keepAliveTime : 线程没有任务执行,最多保持多长时间终止
unit : keepAliveTime的时间单位
threadFactory : 线程工厂,用来创建线程
rejectHandler : 当拒绝处理任务时的策略(1.抛出异常默认策略2.用调用者所在的线程执行任务3.丢弃队列中最靠前的任务来执行当前任务4.丢弃任务)
  可以根据自己的使用场景,来设置审核自己的参数。

execute()方法:提交任务,交给线程池执行

submit()方法:提交任务,能够返回执行结果

shutdown()方法:关闭线程池,等待任务都执行完成

shutdownNow()方法:关闭线程池,不等待任务完成
getTaskCount()方法:线程池已经执行和未执行的任务总数

getCompletedTaskCount()方法:已经完成的任务数量

getPoolSize()方法:线程池当前的线程数量

getActiveCount()方法:当前线程池正在执行任务的线程数量

  根据JDK给我们提供这些方法,我们就可以实时的监控线程池的工作状态。

线程池的创建方式

  一般有两种方式创建线程池,一种是直接调用构造方法,另一种是使用Executors去创建。《阿里巴巴Java开发手册》强制不允许使用Executors创建,因为这样存在一些弊端。
  通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

Executors 返回线程池对象的弊端如下:
FixedThreadPoolSingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。
CachedThreadPoolScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。

使用Executors 创建线程池:

1.Executors.newCachedThreadPool():
  创建一个可以缓存的线程池,返回一个可根据实际情况调整线程数量的线程池。 线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程 在当前任务执行完毕后,将返回线程池进行复用。
2.Executors.newFixedThreadPool(10):
  该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
3.Executors.newScheduledThreadPool(10):
  该方法返回一个固定线程数量的线程池。支持定长,周期性的任务执行。
4.Executors.newSingleThreadExecutor():
  方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。

CachedThreadPool例子:

@Slf4j
public class ThreadPoolExample1 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(() -> {
                log.info("task:{}",index);
            });
        }
        executorService.shutdown();
    }
}
结果是不按大小顺序打印的,这是因为newCachedThreadPool没有限制最大线程数。

FixedThreadPool例子:

@Slf4j
public class ThreadPoolExample2 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(() -> {
                log.info("task:{}",index);
            });
        }
        executorService.shutdown();
    }
}
可以设置一个固定的线程数目。

FixedThreadPool例子:

@Slf4j
public class ThreadPoolExample3 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(() -> {
                log.info("task:{}",index);
            });
        }
        executorService.shutdown();
    }
}
打印结果是有序打印的,因为只有一个线程

ScheduledThreadPool例子:

@Slf4j
public class ThreadPoolExample4 {
    public static void main(String[] args) {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
//        executorService.schedule(() -> {
//            log.warn("schedule run");
//        }, 3, TimeUnit.SECONDS);
        //延迟一秒,每隔三秒执行一次
        executorService.scheduleAtFixedRate(() -> {
            log.warn("schedule run");
        }, 1, 3, TimeUnit.SECONDS);
//        executorService.shutdown();
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                log.warn("timer run");
            }
        }, new Date(), 5 * 1000);
    }
}
有定时器的功能,和Timer类相似。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章