zoukankan      html  css  js  c++  java
  • java(线程池的创建方式,和线程池的原理)

    1.为什么要使用线程池:

     

    1. 减少资源消耗,通过重复的使用已创建好的线程,避免了线程的频繁创建和销毁所造成的消耗
    2. 提高响应速度,当任务到达的时候,不需要再去创建,可以直接使用已经创建好的线程就能立即执行任务
    3. 提高线程的管理性,线程池可以统一管理线程的创建,销毁,分配,调优监控

    2.使用线程池能解决什么问题

      通过固定的几个线程为大量的操作服务,降低线程的频繁创建,销毁线程所需要消耗的时间,从而提高效应效率

    3.线程池的创建方式

     1.5版本通过Executors创建线程池

      

     * @since 1.5
     * @author Doug Lea
     */
    public class Executors {
    
        /**
         * Creates a thread pool that reuses a fixed number of threads
         * operating off a shared unbounded queue.  At any point, at most
         * {@code nThreads} threads will be active processing tasks.
         * If additional tasks are submitted when all threads are active,
         * they will wait in the queue until a thread is available.
         * If any thread terminates due to a failure during execution
         * prior to shutdown, a new one will take its place if needed to
         * execute subsequent tasks.  The threads in the pool will exist
         * until it is explicitly {@link ExecutorService#shutdown shutdown}.
         *
         * @param nThreads the number of threads in the pool
         * @return the newly created thread pool
         * @throws IllegalArgumentException if {@code nThreads <= 0}
         */
        public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }
        public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());
        }

    查看:

    ThreadPoolExecutor(nThreads, nThreads,
                                          0L, TimeUnit.MILLISECONDS,
                                          new LinkedBlockingQueue<Runnable>());

     

     public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue) {
            this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                 Executors.defaultThreadFactory(), defaultHandler);
        }

    corePoolSize: 核心池的大小。 当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中
    maximumPoolSize: 线程池最大线程数,它表示在线程池中最多能创建多少个线程;
    keepAliveTime: 表示线程没有任务执行时最多保持多久时间会终止。
    unit: 参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:

     1.创建一个定长的线程池

      

    package com.thread;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ExecutorsDemo {
        public static void main(String[] args) {
            ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
            for (int i = 0; i < 100; i++) {
    
                final int temp = i;
                newFixedThreadPool.execute(new Runnable() {
    
                    @Override
                    public void run() {
                        System.out.println(Thread.currentThread().getName() + ",i:" + temp);
    
                    }
                });
            }
        }
    }

    上面创建了一个线程池大小为5的线程池,所有的任务都将由这5条线程执行,超出线程会在队列等待 核心线程数==最大线程数

      定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors() 返回虚拟机最大的可用处理器数量

    2.创建一个缓存线程池

     

        public static void createCachedPool() {
            ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
            for (int i = 0; i < 1000000; i++) {
                final int temp = i;
                newCachedThreadPool.execute(new Runnable() {
    
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(100);
                        } catch (Exception e) {
                            // TODO: handle exception
                        }
                        System.out.println(Thread.currentThread().getName() + ",i:" + temp);
    
                    }
                });
            }
    
        }

     缓存线程池,核心线程数为0  最大线程数Integer.MAX_VALUE ,如果有两个任务,第一个线程执行完了其中一个任务,则就继续用该线程执行下一个任务,如果该线程还在执行任务,则创建一个线程执行 最大线程数是 可以认为是无限

    3.创建一个定时周期线程池

     

        public static void createScheduledPool() {
            ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5);
            for (int i = 0; i < 1000; i++) {
                final int temp = i;
                newScheduledThreadPool.schedule(new Runnable() {
                    public void run() {
                        System.out.println("i:" + temp);
                    }
                }, 3, TimeUnit.SECONDS);
            }
        }

     该线程池核心线程是5,最大线程池数Integer.MAX_VALUE,可以设置该线程池里面线程延迟多久执行任务,3表示3s以后再执行任务

    4.创建一个单例线程

     

        public static void createSinglePool() {
            ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
            for (int i = 0; i < 10; i++) {
                final int index = i;
                newSingleThreadExecutor.execute(new Runnable() {
    
                    @Override
                    public void run() {
                        System.out.println("index:" + index);
                        try {
                            Thread.sleep(200);
                        } catch (Exception e) {
                            // TODO: handle exception
                        }
                    }
                });
            }
        }
     public static ExecutorService newSingleThreadExecutor() {
            return new FinalizableDelegatedExecutorService
                (new ThreadPoolExecutor(1, 1,
                                        0L, TimeUnit.MILLISECONDS,
                                        new LinkedBlockingQueue<Runnable>()));
        }

    最大线程数量等于核心线程数量,表示该线程池只会创建一个线程执行任务,执行该任务是有顺序的

    4.线程池原理

     

    提交一个任务到线程池中,线程池的处理流程如下:

    1、判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务。如果核心线程都在执行任务,则进入下个流程。

     

    2、线程池判断工作队列是否已满,如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。

     

    3、判断线程池里的线程是否都处于工作状态,如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

    5.线程池的配置

     

    要想合理的配置线程池,就必须首先分析任务特性,可以从以下几个角度来进行分析:

    任务的性质:CPU密集型任务,IO密集型任务和混合型任务。

    任务的优先级:高,中和低。

    任务的执行时间:长,中和短。

    任务的依赖性:是否依赖其他系统资源,如数据库连接。

    任务性质不同的任务可以用不同规模的线程池分开处理。CPU密集型任务配置尽可能少的线程数量,如配置Ncpu+1个线程的线程池。IO密集型任务则由于需要等待IO操作,线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。混合型的任务,如果可以拆分,则将其拆分成一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。

    优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先得到执行,需要注意的是如果一直有优先级高的任务提交到队列里,那么优先级低的任务可能永远不能执行。

    执行时间不同的任务可以交给不同规模的线程池来处理,或者也可以使用优先级队列,让执行时间短的任务先执行。

    依赖数据库连接池的任务,因为线程提交SQL后需要等待数据库返回结果,如果等待的时间越长CPU空闲时间就越长,那么线程数应该设置越大,这样才能更好的利用CPU。

     

    CPU密集型时,任务可以少配置线程数,大概和机器的cpu核数相当,这样可以使得每个线程都在执行任务

    IO密集型时,大部分线程都阻塞,故需要多配置线程数,2*cpu核数

    操作系统之名称解释:

    某些进程花费了绝大多数时间在计算上,而其他则在等待I/O上花费了大多是时间,

    前者称为计算密集型(CPU密集型)computer-bound,后者称为I/O密集型

  • 相关阅读:
    AjaxPro.HttpSessionStateRequirement.ReadWrite
    C#关键字abstract virtual interface new override
    ASP.NET ViewState详解
    DataTable的Select方法
    DWR学习笔记 Hello World
    JSP标签分页实现
    php图片验证码类
    使用php发送Http请求,抓取网页数据
    JdbcTemplate 排序查询结果不一致问题
    ANT 和 JDK 的设置
  • 原文地址:https://www.cnblogs.com/920913cheng/p/11368783.html
Copyright © 2011-2022 走看看