zoukankan      html  css  js  c++  java
  • JAVA多线程提高六:java5线程并发库的应用_线程池

    前面我们对并发有了一定的认识,并且知道如何创建线程,创建线程主要依靠的是Thread 的类来完成的,那么有什么缺陷呢?如何解决?

    一、对比new Thread
    new Thread的弊端
    a. 每次new Thread新建对象性能差。
    b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
    c. 缺乏更多功能,如定时执行、定期执行、线程中断。
    相比new Thread,Java提供的四种线程池的好处在于:
    a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
    b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
    c. 提供定时执行、定期执行、单线程、并发数控制等功能。

    二、创建线程池方法

    一般通过调用Executors的工厂方法创建线程池,常用的有以下5种类:

    //创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
    Executors.newFixedThreadPool
    //创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
    Executors.newSingleThreadExecutor
    //创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
    Executors.newCachedThreadPool
    //创建一个定长线程池,支持定时及周期性任务执行
    Executors.newScheduledThreadPool
    //创建一个单线程化的线程池,支持定时及周期性任务执行
    Executors.newSingleThreadScheduledExecutor

    上面每种出基本的参数使用外,还可以根据个人需要加入ThreadFactory(java的线程生成工厂,可以自己重写做些命名日志之类)参数。如:newFixedThreadPool有重载两种方法:newFixedThreadPool(int) 和 newFixedThreadPool(int,ThreadFactory)

    调用上面的方法其实都是创建ThreadPoolExecutor对象,只是传入的参数不同而已。 
    ThreadPoolExecutor的类方法:ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, ...),可定义线程池固定的线程数及最大线程数。

    三、执行

    一般通过调用execute(Runnable) 或者 submit(Callable)执行线程

    四、关闭

    详细可参考: 
    深入理解JAVA–线程池(二):shutdown、shutdownNow、awaitTermination 
    JAVA线程池shutdown和shutdownNow的区别 
    threadPoolExecutor 中的 shutdown() 、 shutdownNow() 、 awaitTermination() 的用法和区别

    threadPool.shutdown(): 不接受新任务,已提交的任务继续执行

    Initiates an orderly shutdown in which previously submitted 
    tasks are executed, but no new tasks will be accepted. 
    Invocation has no additional effect if already shut down.

    List<Runnable> shutdownNow(): 阻止新来的任务提交,同时会尝试中断当前正在运行的线程,返回等待执行的任务列表

    Attempts to stop all actively executing tasks, halts the 
    processing of waiting tasks, and returns a list of the tasks 
    that were awaiting execution.

    awaitTermination(long timeout, TimeUnit unit):等所有已提交的任务(包括正在跑的和队列中等待的)执行完或者超时或者被中断。

    线程池状态: 
    isShutdown():if this executor has been shut down. 
    isTerminated():if all tasks have completed following shut down.isTerminated is never true unless either shutdown or shutdownNow was called first

    如何选择: 
    * 优雅的关闭,用shutdown() 
    * 想立马关闭,并得到未执行任务列表,用shutdownNow() 
    * 优雅的关闭,并允许关闭声明后新任务能提交,用awaitTermination()

    五、常用线程池

    newFixedThreadPool

    要应用场景:固定线程数的线程池比较常见,如处理网络请求等。常用!!!

    使用示例

    / 调用execute
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);  
    for (int i = 0; i < 10; i++) {  
        final int index = i;  
        fixedThreadPool.execute(new Runnable() {  
            public void run() {    
            System.out.println(index);  
        });  
    }  
    
    // 调用submit
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    List<Future> futureList = new ArrayList<Future>();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        futureList.add(fixedThreadPool.submit(new Callable<Integer>() {
            public Integer call() throws Exception {
                return index;
            }
        }));
    }
    for(Future future : futureList) {
        try {
            future.get();
        } catch (Exception e) {
            future.cancel(true);
        }
    }

    newCachedThreadPool

    主要应用场景:需要很极致的速度,因为newCachedThreadPool不会等待空闲线程。但有一定风险,如果一个任务很慢或者阻塞,并且请求很多,就容易造成线程泛滥,会导致整个系统的假死(无法接收处理新的请求),所以实际上个人不建议使用这个方法。

    使用示例:execute、submit类似于newFixedThreadPool

    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();  
    for (int i = 0; i < 10; i++) {  
        final int index = i;  
        cachedThreadPool.execute(new Runnable() {  
            public void run() {  
                System.out.println(index);  
            }  
        });  
    }

    newSingleThreadExecutor

    使用示例:execute、submit类似于newFixedThreadPool

    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();  
    for (int i = 0; i < 10; i++) {
      final int index = i;  
      singleThreadExecutor.execute(new Runnable() {
        public void run() {  
        System.out.println(index);  
      });  
    }  

    newScheduledThreadPool

    执行newScheduledThreadPool返回类ScheduledExecutorService(其实新建类ScheduledThreadPoolExecutor)。 
    通过类ScheduledThreadPoolExecutor的定义:class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService及源码可知: 
    1、ScheduledThreadPoolExecutor是ScheduledExecutorService的实现类。 
    2、ScheduledThreadPoolExecutor继承了类ThreadPoolExecutor

    通常我们通过Executors工厂方法(Executors.newScheduledThreadPool)获取类ScheduledExecutorService或直接通过new ScheduledThreadPoolExecutor类创建定时任务。

    ScheduledThreadPoolExecutor有以下重载方法: 
    方法返回接口:ScheduledFuture。接口定义为:public interface ScheduledFuture<V> extends Delayed, Future<V>。对应着有以下几种常用的方法: 
    cancel:取消任务 
    getDelay:获取任务还有多久执行


    public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) 
    延迟delay执行,只执行一次

    使用示例

    // 延迟3s执行
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
    scheduledThreadPool.schedule(new Runnable() {  
      public void run() {  
        System.out.println("delay 3 seconds");  
      }  
    }, 3, TimeUnit.SECONDS); 
    
    //延迟1秒后每3秒执行一次
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
    ScheduledFuture<?> scheduledFuture = scheduledThreadPool.scheduleAtFixedRate(new Runnable() {  
      public void run() {  
        System.out.println("delay 1 seconds, and excute every 3 seconds");  
      }  
    }, 1, 3, TimeUnit.SECONDS);  
    
    //获取下一次任务还有多久执行
    scheduledFuture.getDelay(TimeUnit.SECONDS)

    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
    延迟initialDelay开始执行执行,之后周期period执行,类比Timer的scheduleAtFixedRate方法,固定频率执行。当某个任务执行的时间超过period时间,则可能导致下一个定时任务延迟,但是不会出现并发执行的情况。当任何一个任务执行跑出异常,后面的任务将不会执行。所以你如果想保住任务都一直被周期执行,那么catch一切可能的异常。通过取消任务(调用cancel方法)或者终止executor(调用shutdown方法)可使任务停止。


    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) 
    延迟initialDelay开始执行执行,之后周期period执行,类比Timer的schedule方法,固定延迟执行。当上一个任务执行后,等待delay时间才执行下一个,因此也不会并发执行的情况。当任何一个任务执行跑出异常,后面的任务将不会执行。所以你如果想保住任务都一直被周期执行,那么catch一切可能的异常。通过取消任务(调用cancel方法)或者终止executor(调用shutdown方法)可使任务停止。

    六、ScheduledThreadPoolExecutor与Timer的区别

    直接参考:Timer与ScheduledThreadPoolExecutor

    参考:

    java常用线程池 
    Java 四种线程池的用法分析 
    JAVA线程池shutdown和shutdownNow的区别

  • 相关阅读:
    组播IP地址
    改变未来的10大科技
    知行合一之健康
    2017第47周五
    2017第47周四感恩节
    spring boot测试
    2017第47周二
    音频格式opus
    周日反思
    四种人工智能技术对五个行业的影响
  • 原文地址:https://www.cnblogs.com/pony1223/p/9286519.html
Copyright © 2011-2022 走看看