线程池 订阅
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。 展开全文
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。
信息
适用范围
互联网
类    别
多线程处理形式
中文名
线程池
外文名
thread pool
线程池简介
线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。任务调度以执行线程的常见方法是使用同步队列,称作任务队列。池中的线程等待队列中的任务,并把执行完的任务放入完成队列中。线程池模式一般分为两种:HS/HA半同步/半异步模式、L/F领导者与跟随者模式。线程池的伸缩性对性能有较大的影响。
收起全文
精华内容
参与话题
问答
  • 线程池的原理及实现

    万次阅读 多人点赞 2013-05-28 17:50:44
    1、线程池简介:  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。   假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在...

    1、线程池简介:
        多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。   
        假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。

        如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
                    一个线程池包括以下四个基本组成部分:
                    1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
                    2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
                    3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
                    4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
                   
        线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
        线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
        假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

        代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了

     

    1. package mine.util.thread;  
    2.   
    3. import java.util.LinkedList;  
    4. import java.util.List;  
    5.   
    6. /** 
    7.  * 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息 
    8.  */  
    9. public final class ThreadPool {  
    10.     // 线程池中默认线程的个数为5  
    11.     private static int worker_num = 5;  
    12.     // 工作线程  
    13.     private WorkThread[] workThrads;  
    14.     // 未处理的任务  
    15.     private static volatile int finished_task = 0;  
    16.     // 任务队列,作为一个缓冲,List线程不安全  
    17.     private List<Runnable> taskQueue = new LinkedList<Runnable>();  
    18.     private static ThreadPool threadPool;  
    19.   
    20.     // 创建具有默认线程个数的线程池  
    21.     private ThreadPool() {  
    22.         this(5);  
    23.     }  
    24.   
    25.     // 创建线程池,worker_num为线程池中工作线程的个数  
    26.     private ThreadPool(int worker_num) {  
    27.         ThreadPool.worker_num = worker_num;  
    28.         workThrads = new WorkThread[worker_num];  
    29.         for (int i = 0; i < worker_num; i++) {  
    30.             workThrads[i] = new WorkThread();  
    31.             workThrads[i].start();// 开启线程池中的线程  
    32.         }  
    33.     }  
    34.   
    35.     // 单态模式,获得一个默认线程个数的线程池  
    36.     public static ThreadPool getThreadPool() {  
    37.         return getThreadPool(ThreadPool.worker_num);  
    38.     }  
    39.   
    40.     // 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数  
    41.     // worker_num<=0创建默认的工作线程个数  
    42.     public static ThreadPool getThreadPool(int worker_num1) {  
    43.         if (worker_num1 <= 0)  
    44.             worker_num1 = ThreadPool.worker_num;  
    45.         if (threadPool == null)  
    46.             threadPool = new ThreadPool(worker_num1);  
    47.         return threadPool;  
    48.     }  
    49.   
    50.     // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    51.     public void execute(Runnable task) {  
    52.         synchronized (taskQueue) {  
    53.             taskQueue.add(task);  
    54.             taskQueue.notify();  
    55.         }  
    56.     }  
    57.   
    58.     // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    59.     public void execute(Runnable[] task) {  
    60.         synchronized (taskQueue) {  
    61.             for (Runnable t : task)  
    62.                 taskQueue.add(t);  
    63.             taskQueue.notify();  
    64.         }  
    65.     }  
    66.   
    67.     // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  
    68.     public void execute(List<Runnable> task) {  
    69.         synchronized (taskQueue) {  
    70.             for (Runnable t : task)  
    71.                 taskQueue.add(t);  
    72.             taskQueue.notify();  
    73.         }  
    74.     }  
    75.   
    76.     // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁  
    77.     public void destroy() {  
    78.         while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧  
    79.             try {  
    80.                 Thread.sleep(10);  
    81.             } catch (InterruptedException e) {  
    82.                 e.printStackTrace();  
    83.             }  
    84.         }  
    85.         // 工作线程停止工作,且置为null  
    86.         for (int i = 0; i < worker_num; i++) {  
    87.             workThrads[i].stopWorker();  
    88.             workThrads[i] = null;  
    89.         }  
    90.         threadPool=null;  
    91.         taskQueue.clear();// 清空任务队列  
    92.     }  
    93.   
    94.     // 返回工作线程的个数  
    95.     public int getWorkThreadNumber() {  
    96.         return worker_num;  
    97.     }  
    98.   
    99.     // 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成  
    100.     public int getFinishedTasknumber() {  
    101.         return finished_task;  
    102.     }  
    103.   
    104.     // 返回任务队列的长度,即还没处理的任务个数  
    105.     public int getWaitTasknumber() {  
    106.         return taskQueue.size();  
    107.     }  
    108.   
    109.     // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数  
    110.     @Override  
    111.     public String toString() {  
    112.         return "WorkThread number:" + worker_num + "  finished task number:"  
    113.                 + finished_task + "  wait task number:" + getWaitTasknumber();  
    114.     }  
    115.   
    116.     /** 
    117.      * 内部类,工作线程 
    118.      */  
    119.     private class WorkThread extends Thread {  
    120.         // 该工作线程是否有效,用于结束该工作线程  
    121.         private boolean isRunning = true;  
    122.   
    123.         /* 
    124.          * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待 
    125.          */  
    126.         @Override  
    127.         public void run() {  
    128.             Runnable r = null;  
    129.             while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了  
    130.                 synchronized (taskQueue) {  
    131.                     while (isRunning && taskQueue.isEmpty()) {// 队列为空  
    132.                         try {  
    133.                             taskQueue.wait(20);  
    134.                         } catch (InterruptedException e) {  
    135.                             e.printStackTrace();  
    136.                         }  
    137.                     }  
    138.                     if (!taskQueue.isEmpty())  
    139.                         r = taskQueue.remove(0);// 取出任务  
    140.                 }  
    141.                 if (r != null) {  
    142.                     r.run();// 执行任务  
    143.                 }  
    144.                 finished_task++;  
    145.                 r = null;  
    146.             }  
    147.         }  
    148.   
    149.         // 停止工作,让该线程自然执行完run方法,自然结束  
    150.         public void stopWorker() {  
    151.             isRunning = false;  
    152.         }  
    153.     }  
    154. }  

     

    测试代码:

    1. package mine.util.thread;  
    2.   
    3. //测试线程池  
    4. public class TestThreadPool {  
    5.     public static void main(String[] args) {  
    6.         // 创建3个线程的线程池  
    7.         ThreadPool t = ThreadPool.getThreadPool(3);  
    8.         t.execute(new Runnable[] { new Task(), new Task(), new Task() });  
    9.         t.execute(new Runnable[] { new Task(), new Task(), new Task() });  
    10.         System.out.println(t);  
    11.         t.destroy();// 所有线程都执行完成才destory  
    12.         System.out.println(t);  
    13.     }  
    14.   
    15.     // 任务类  
    16.     static class Task implements Runnable {  
    17.         private static volatile int i = 1;  
    18.   
    19.         @Override  
    20.         public void run() {// 执行任务  
    21.             System.out.println("任务 " + (i++) + " 完成");  
    22.         }  
    23.     }  
    24. }  


     

    运行结果:

    WorkThread number:3  finished task number:0  wait task number:6
    任务 1 完成
    任务 2 完成
    任务 3 完成
    任务 4 完成
    任务 5 完成
    任务 6 完成
    WorkThread number:3  finished task number:6  wait task number:0

    分析:由于并没有任务接口,传入的可以是自定义的任何任务,所以线程池并不能准确的判断该任务是否真正的已经完成(真正完成该任务是这个任务的run方法执行完毕),只能知道该任务已经出了任务队列,正在执行或者已经完成。

    2、java类库中提供的线程池简介:

         java提供的线程池更加强大,相信理解线程池的工作原理,看类库中的线程池就不会感到陌生了。

    展开全文
  • Java多线程:彻底搞懂线程池

    万次阅读 多人点赞 2019-07-09 19:27:00
    熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。 目录 1 线程池的优势 2 线程池的使用 3 线程池的工作原理 4 线程池的参数 4.1 任务队列...

    熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。

    目录

    1 线程池的优势

    2 线程池的使用

    3 线程池的工作原理

    4 线程池的参数

    4.1 任务队列(workQueue)

    4.2 线程工厂(threadFactory)

    4.3 拒绝策略(handler)

    5 功能线程池

    5.1 定长线程池(FixedThreadPool)

    5.2 定时线程池(ScheduledThreadPool )

    5.3 可缓存线程池(CachedThreadPool)

    5.4 单线程化线程池(SingleThreadExecutor)

    5.5 对比

    6 总结

    参考


    1 线程池的优势

    总体来说,线程池有如下的优势:

    (1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

    (2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

    (3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

    2 线程池的使用

    线程池的真正实现类是ThreadPoolExecutor,其构造方法有如下4种:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }
    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
    
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

    可以看到,其需要如下几个参数:

    • corePoolSize(必需):核心线程数。默认情况下,核心线程会一直存活,但是当将allowCoreThreadTimeout设置为true时,核心线程也会超时回收。
    • maximumPoolSize(必需):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。
    • keepAliveTime(必需):线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将allowCoreThreadTimeout设置为true时,核心线程也会超时回收。
    • unit(必需):指定keepAliveTime参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。
    • workQueue(必需):任务队列。通过线程池的execute()方法提交的Runnable对象将存储在该参数中。其采用阻塞队列实现。
    • threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。
    • handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。

    线程池的使用流程如下:

    // 创建线程池
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,
                                                 MAXIMUM_POOL_SIZE,
                                                 KEEP_ALIVE,
                                                 TimeUnit.SECONDS,
                                                 sPoolWorkQueue,
                                                 sThreadFactory);
    // 向线程池提交任务
    threadPool.execute(new Runnable() {
        @Override
        public void run() {
            ... // 线程执行的任务
        }
    });
    // 关闭线程池
    threadPool.shutdown(); // 设置线程池的状态为SHUTDOWN,然后中断所有没有正在执行任务的线程
    threadPool.shutdownNow(); // 设置线程池的状态为 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表

    3 线程池的工作原理

    下面来描述一下线程池工作的原理,同时对上面的参数有一个更深的了解。其工作原理流程图如下:

    通过上图,相信大家已经对所有参数有个了解了。下面再对任务队列、线程工厂和拒绝策略做更多的说明。

    4 线程池的参数

    4.1 任务队列(workQueue)

    任务队列是基于阻塞队列实现的,即采用生产者消费者模式,在Java中需要实现BlockingQueue接口。但Java已经为我们提供了7种阻塞队列的实现:

    1. ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列(数组结构可配合指针实现一个环形队列)。
    2. LinkedBlockingQueue: 一个由链表结构组成的有界阻塞队列,在未指明容量时,容量默认为Integer.MAX_VALUE
    3. PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列,对元素没有要求,可以实现Comparable接口也可以提供Comparator来对队列中的元素进行比较。跟时间没有任何关系,仅仅是按照优先级取任务。
    4. DelayQueue:类似于PriorityBlockingQueue,是二叉堆实现的无界优先级阻塞队列。要求元素都实现Delayed接口,通过执行时延从队列中提取任务,时间没到任务取不出来。
    5. SynchronousQueue: 一个不存储元素的阻塞队列,消费者线程调用take()方法的时候就会发生阻塞,直到有一个生产者线程生产了一个元素,消费者线程就可以拿到这个元素并返回;生产者线程调用put()方法的时候也会发生阻塞,直到有一个消费者线程消费了一个元素,生产者才会返回。
    6. LinkedBlockingDeque: 使用双向队列实现的有界双端阻塞队列。双端意味着可以像普通队列一样FIFO(先进先出),也可以像栈一样FILO(先进后出)。
    7. LinkedTransferQueue: 它是ConcurrentLinkedQueueLinkedBlockingQueueSynchronousQueue的结合体,但是把它用在ThreadPoolExecutor中,和LinkedBlockingQueue行为一致,但是是无界的阻塞队列。

    注意有界队列和无界队列的区别:如果使用有界队列,当队列饱和时并超过最大线程数时就会执行拒绝策略;而如果使用无界队列,因为任务队列永远都可以添加任务,所以设置maximumPoolSize没有任何意义。

    4.2 线程工厂(threadFactory)

    线程工厂指定创建线程的方式,需要实现ThreadFactory接口,并实现newThread(Runnable r)方法。该参数可以不用指定,Executors框架已经为我们实现了一个默认的线程工厂:

    /**
     * The default thread factory.
     */
    private static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
    
        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }
    
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

    4.3 拒绝策略(handler)

    当线程池的线程数达到最大线程数时,需要执行拒绝策略。拒绝策略需要实现RejectedExecutionHandler接口,并实现rejectedExecution(Runnable r, ThreadPoolExecutor executor)方法。不过Executors框架已经为我们实现了4种拒绝策略:

    1. AbortPolicy(默认):丢弃任务并抛出RejectedExecutionException异常。
    2. CallerRunsPolicy:由调用线程处理该任务。
    3. DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
    4. DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。

    5 功能线程池

    嫌上面使用线程池的方法太麻烦?其实Executors已经为我们封装好了4种常见的功能线程池,如下:

    • 定长线程池(FixedThreadPool)
    • 定时线程池(ScheduledThreadPool )
    • 可缓存线程池(CachedThreadPool)
    • 单线程化线程池(SingleThreadExecutor)

    5.1 定长线程池(FixedThreadPool)

    创建方法的源码:

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }
    • 特点:只有核心线程,线程数量固定,执行完立即回收,任务队列为链表结构的有界队列。
    • 应用场景:控制线程最大并发数。

    使用示例:

    // 1. 创建定长线程池对象 & 设置线程池线程数量固定为3
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    // 2. 创建好Runnable类线程对象 & 需执行的任务
    Runnable task =new Runnable(){
      public void run() {
         System.out.println("执行任务啦");
      }
    };
    // 3. 向线程池提交任务
    fixedThreadPool.execute(task);

    5.2 定时线程池(ScheduledThreadPool )

    创建方法的源码:

    private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
    
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }
    
    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize,
                                       ThreadFactory threadFactory) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue(), threadFactory);
    }
    • 特点:核心线程数量固定,非核心线程数量无限,执行完闲置10ms后回收,任务队列为延时阻塞队列。
    • 应用场景:执行定时或周期性的任务。

    使用示例:

    // 1. 创建 定时线程池对象 & 设置线程池线程数量固定为5
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    // 2. 创建好Runnable类线程对象 & 需执行的任务
    Runnable task =new Runnable(){
      public void run() {
         System.out.println("执行任务啦");
      }
    };
    // 3. 向线程池提交任务
    scheduledThreadPool.schedule(task, 1, TimeUnit.SECONDS); // 延迟1s后执行任务
    scheduledThreadPool.scheduleAtFixedRate(task,10,1000,TimeUnit.MILLISECONDS);// 延迟10ms后、每隔1000ms执行任务

    5.3 可缓存线程池(CachedThreadPool)

    创建方法的源码:

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }
    • 特点:无核心线程,非核心线程数量无限,执行完闲置60s后回收,任务队列为不存储元素的阻塞队列。
    • 应用场景:执行大量、耗时少的任务。

    使用示例:

    // 1. 创建可缓存线程池对象
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    // 2. 创建好Runnable类线程对象 & 需执行的任务
    Runnable task =new Runnable(){
      public void run() {
         System.out.println("执行任务啦");
      }
    };
    // 3. 向线程池提交任务
    cachedThreadPool.execute(task);

    5.4 单线程化线程池(SingleThreadExecutor)

    创建方法的源码:

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }
    • 特点:只有1个核心线程,无非核心线程,执行完立即回收,任务队列为链表结构的有界队列。
    • 应用场景:不适合并发但可能引起IO阻塞性及影响UI线程响应的操作,如数据库操作、文件操作等。

    使用示例:

    // 1. 创建单线程化线程池
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    // 2. 创建好Runnable类线程对象 & 需执行的任务
    Runnable task =new Runnable(){
      public void run() {
         System.out.println("执行任务啦");
      }
    };
    // 3. 向线程池提交任务
    singleThreadExecutor.execute(task);

    5.5 对比

    6 总结

    Executors的4个功能线程池虽然方便,但现在已经不建议使用了,而是建议直接通过使用ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。

    其实Executors的4个功能线程有如下弊端:

    • FixedThreadPoolSingleThreadExecutor:主要问题是堆积的请求处理队列均采用LinkedBlockingQueue,可能会耗费非常大的内存,甚至OOM。
    • CachedThreadPoolScheduledThreadPool:主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

     

    参考

     

    展开全文
  • 4种常用线程池介绍

    万次阅读 多人点赞 2018-05-09 14:58:52
    使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,...

    一. 线程池简介

    1. 线程池的概念:

              线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。

    2. 线程池的工作机制

             2.1 在线程池的编程模式下,任务是提交给整个线程池,而不是直接提交给某个线程,线程池在拿到任务后,就在内部寻找是否有空闲的线程,如果有,则将任务交给某个空闲的线程。

             2.1 一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。

    3. 使用线程池的原因:

            多线程运行时间,系统不断的启动和关闭新线程,成本非常高,会过渡消耗系统资源,以及过渡切换线程的危险,从而可能导致系统资源的崩溃。这时,线程池就是最好的选择了。

    二. 四种常见的线程池详解

    1. 线程池的返回值ExecutorService简介:

             ExecutorService是Java提供的用于管理线程池的接口。该接口的两个作用:控制线程数量和重用线程

    2. 具体的4种常用的线程池实现如下:(返回值都是ExecutorService)

             2.1 Executors.newCacheThreadPool():可缓存线程池,先查看池中有没有以前建立的线程,如果有,就直接使用。如果没有,就建一个新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务

             示例代码:

    复制代码
     1 package com.study.test;
     2 
     3 import java.util.concurrent.ExecutorService;
     4 import java.util.concurrent.Executors;
     5 
     6 public class ThreadPoolExecutorTest {
     7     public static void main(String[] args) {
     8         //创建一个可缓存线程池
     9         ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    10         for (int i = 0; i < 10; i++) {
    11             try {
    12                 //sleep可明显看到使用的是线程池里面以前的线程,没有创建新的线程
    13                 Thread.sleep(1000);
    14             } catch (InterruptedException e) {
    15                 e.printStackTrace();
    16             }
    17             cachedThreadPool.execute(new Runnable() {
    18                 public void run() {
    19                     //打印正在执行的缓存线程信息
    20                     System.out.println(Thread.currentThread().getName()+"正在被执行");
    21                 }
    22             });
    23         }
    24     }
    25 }
    复制代码

    输出结果:

    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-1正在被执行

    线程池为无限大,当执行当前任务时上一个任务已经完成,会复用执行上一个任务的线程,而不用每次新建线程

           2.2  Executors.newFixedThreadPool(int n):创建一个可重用固定个数的线程池,以共享的无界队列方式来运行这些线程。

             示例代码:

    复制代码
     1 package com.study.test;
     2 
     3 import java.util.concurrent.ExecutorService;
     4 import java.util.concurrent.Executors;
     5 
     6 public class ThreadPoolExecutorTest {
     7     public static void main(String[] args) {
     8         //创建一个可重用固定个数的线程池
     9         ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    10         for (int i = 0; i < 10; i++) {
    11             fixedThreadPool.execute(new Runnable() {
    12                 public void run() {
    13                     try {
    14                         //打印正在执行的缓存线程信息
    15                         System.out.println(Thread.currentThread().getName()+"正在被执行");
    16                         Thread.sleep(2000);
    17                     } catch (InterruptedException e) {
    18                         e.printStackTrace();
    19                     }
    20                 }
    21             });
    22         }
    23     }
    24 }
    复制代码

    输出结果:

    pool-1-thread-1正在被执行
    pool-1-thread-2正在被执行
    pool-1-thread-3正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-2正在被执行
    pool-1-thread-3正在被执行
    pool-1-thread-1正在被执行
    pool-1-thread-2正在被执行
    pool-1-thread-3正在被执行
    pool-1-thread-1正在被执行

    因为线程池大小为3,每个任务输出打印结果后sleep 2秒,所以每两秒打印3个结果。
    定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()

           2.3  Executors.newScheduledThreadPool(int n):创建一个定长线程池,支持定时及周期性任务执行

                 延迟执行示例代码:

    复制代码
     1 package com.study.test;
     2 
     3 import java.util.concurrent.Executors;
     4 import java.util.concurrent.ScheduledExecutorService;
     5 import java.util.concurrent.TimeUnit;
     6 
     7 public class ThreadPoolExecutorTest {
     8     public static void main(String[] args) {
     9         //创建一个定长线程池,支持定时及周期性任务执行——延迟执行
    10         ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    11         //延迟1秒执行
    12         scheduledThreadPool.schedule(new Runnable() {
    13             public void run() {
    14                 System.out.println("延迟1秒执行");
    15             }
    16         }, 1, TimeUnit.SECONDS);
    17     }
    18 }
    复制代码

    输出结果:延迟1秒执行

                 定期执行示例代码:

    复制代码
     1 package com.study.test;
     2 
     3 import java.util.concurrent.Executors;
     4 import java.util.concurrent.ScheduledExecutorService;
     5 import java.util.concurrent.TimeUnit;
     6 
     7 public class ThreadPoolExecutorTest {
     8     public static void main(String[] args) {
     9         //创建一个定长线程池,支持定时及周期性任务执行——定期执行
    10         ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    11         //延迟1秒后每3秒执行一次
    12         scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
    13             public void run() {
    14                 System.out.println("延迟1秒后每3秒执行一次");
    15             }
    16         }, 1, 3, TimeUnit.SECONDS);
    17     }
    18 }
    复制代码

    输出结果:

    延迟1秒后每3秒执行一次
    延迟1秒后每3秒执行一次
    .............

            2.4  Executors.newSingleThreadExecutor():创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

                   示例代码: 

    复制代码
     1 package com.study.test;
     2 
     3 import java.util.concurrent.ExecutorService;
     4 import java.util.concurrent.Executors;
     5 
     6 public class TestThreadPoolExecutor {
     7     public static void main(String[] args) {
     8         //创建一个单线程化的线程池
     9         ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    10         for (int i = 0; i < 10; i++) {
    11             final int index = i;
    12             singleThreadExecutor.execute(new Runnable() {
    13                 public void run() {
    14                     try {
    15                         //结果依次输出,相当于顺序执行各个任务
    16                         System.out.println(Thread.currentThread().getName()+"正在被执行,打印的值是:"+index);
    17                         Thread.sleep(1000);
    18                     } catch (InterruptedException e) {
    19                         e.printStackTrace();
    20                     }
    21                 }
    22             });
    23         }
    24     }
    25 }
    复制代码

    输出结果:

    pool-1-thread-1正在被执行,打印的值是:0
    pool-1-thread-1正在被执行,打印的值是:1
    pool-1-thread-1正在被执行,打印的值是:2
    pool-1-thread-1正在被执行,打印的值是:3
    pool-1-thread-1正在被执行,打印的值是:4
    pool-1-thread-1正在被执行,打印的值是:5
    pool-1-thread-1正在被执行,打印的值是:6
    pool-1-thread-1正在被执行,打印的值是:7
    pool-1-thread-1正在被执行,打印的值是:8
    pool-1-thread-1正在被执行,打印的值是:9

    三. 缓冲队列BlockingQueue和自定义线程池ThreadPoolExecutor

    1. 缓冲队列BlockingQueue简介:

              BlockingQueue是双缓冲队列。BlockingQueue内部使用两条队列,允许两个线程同时向队列一个存储,一个取出操作。在保证并发安全的同时,提高了队列的存取效率。

    2. 常用的几种BlockingQueue:

    • ArrayBlockingQueue(int i):规定大小的BlockingQueue,其构造必须指定大小。其所含的对象是FIFO顺序排序的。

    • LinkedBlockingQueue()或者(int i):大小不固定的BlockingQueue,若其构造时指定大小,生成的BlockingQueue有大小限制,不指定大小,其大小有Integer.MAX_VALUE来决定。其所含的对象是FIFO顺序排序的。

    • PriorityBlockingQueue()或者(int i):类似于LinkedBlockingQueue,但是其所含对象的排序不是FIFO,而是依据对象的自然顺序或者构造函数的Comparator决定。

    • SynchronizedQueue():特殊的BlockingQueue,对其的操作必须是放和取交替完成。

    3. 自定义线程池(ThreadPoolExecutor和BlockingQueue连用):

         自定义线程池,可以用ThreadPoolExecutor类创建,它有多个构造方法来创建线程池。

        常见的构造函数:ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)

         示例代码:

    复制代码
     1 package com.study.test;
     2 
     3 import java.util.concurrent.ArrayBlockingQueue;
     4 import java.util.concurrent.BlockingQueue;
     5 import java.util.concurrent.ThreadPoolExecutor;
     6 import java.util.concurrent.TimeUnit;
     7 
     8 class TempThread implements Runnable {
     9 
    10     @Override
    11     public void run() {
    12         // 打印正在执行的缓存线程信息
    13         System.out.println(Thread.currentThread().getName() + "正在被执行");
    14         try {
    15             // sleep一秒保证3个任务在分别在3个线程上执行
    16             Thread.sleep(1000);
    17         } catch (InterruptedException e) {
    18             e.printStackTrace();
    19         }
    20     }
    21 
    22 }
    23 
    24 public class TestThreadPoolExecutor {
    25     public static void main(String[] args) {
    26         // 创建数组型缓冲等待队列
    27         BlockingQueue<Runnable> bq = new ArrayBlockingQueue<Runnable>(10);
    28         // ThreadPoolExecutor:创建自定义线程池,池中保存的线程数为3,允许最大的线程数为6
    29         ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 6, 50, TimeUnit.MILLISECONDS, bq);
    30 
    31         // 创建3个任务
    32         Runnable t1 = new TempThread();
    33         Runnable t2 = new TempThread();
    34         Runnable t3 = new TempThread();
    35         // Runnable t4 = new TempThread();
    36         // Runnable t5 = new TempThread();
    37         // Runnable t6 = new TempThread();
    38 
    39         // 3个任务在分别在3个线程上执行
    40         tpe.execute(t1);
    41         tpe.execute(t2);
    42         tpe.execute(t3);
    43         // tpe.execute(t4);
    44         // tpe.execute(t5);
    45         // tpe.execute(t6);
    46 
    47         // 关闭自定义线程池
    48         tpe.shutdown();
    49     }
    50 }
    复制代码

    输出结果:

    pool-1-thread-1正在被执行
    pool-1-thread-2正在被执行
    pool-1-thread-3正在被执行

    展开全文
  • 深入理解线程和线程池(图文详解)

    万次阅读 多人点赞 2018-04-19 00:51:36
    关于线程和线程池的学习,我们可以从以下几个方面入手:第一,什么是线程,线程和进程的区别是什么第二,线程中的基本概念,线程的生命周期第三,单线程和多线程第四,线程池的原理解析第五,常见的几种线程池的特点...

    关于线程和线程池的学习,我们可以从以下几个方面入手:

    第一,什么是线程,线程和进程的区别是什么

    第二,线程中的基本概念,线程的生命周期

    第三,单线程和多线程

    第四,线程池的原理解析

    第五,常见的几种线程池的特点以及各自的应用场景


    一、

    线程,程序执行流的最小执行单位,是行程中的实际运作单位,经常容易和进程这个概念混淆。那么,线程和进程究竟有什么区别呢?首先,进程是一个动态的过程,是一个活动的实体。简单来说,一个应用程序的运行就可以被看做是一个进程,而线程,是运行中的实际的任务执行者。可以说,进程中包含了多个可以同时运行的线程。


    二、

    线程的生命周期,线程的生命周期可以利用以下的图解来更好的理解:


    第一步,是用new Thread()的方法新建一个线程,在线程创建完成之后,线程就进入了就绪(Runnable)状态,此时创建出来的线程进入抢占CPU资源的状态,当线程抢到了CPU的执行权之后,线程就进入了运行状态(Running),当该线程的任务执行完成之后或者是非常态的调用的stop()方法之后,线程就进入了死亡状态。而我们在图解中可以看出,线程还具有一个则色的过程,这是怎么回事呢?当面对以下几种情况的时候,容易造成线程阻塞,第一种,当线程主动调用了sleep()方法时,线程会进入则阻塞状态,除此之外,当线程中主动调用了阻塞时的IO方法时,这个方法有一个返回参数,当参数返回之前,线程也会进入阻塞状态,还有一种情况,当线程进入正在等待某个通知时,会进入阻塞状态。那么,为什么会有阻塞状态出现呢?我们都知道,CPU的资源是十分宝贵的,所以,当线程正在进行某种不确定时长的任务时,Java就会收回CPU的执行权,从而合理应用CPU的资源。我们根据图可以看出,线程在阻塞过程结束之后,会重新进入就绪状态,重新抢夺CPU资源。这时候,我们可能会产生一个疑问,如何跳出阻塞过程呢?又以上几种可能造成线程阻塞的情况来看,都是存在一个时间限制的,当sleep()方法的睡眠时长过去后,线程就自动跳出了阻塞状态,第二种则是在返回了一个参数之后,在获取到了等待的通知时,就自动跳出了线程的阻塞过程

    三、

    什么是单线程和多线程?

    单线程,顾名思义即是只有一条线程在执行任务,这种情况在我们日常的工作学习中很少遇到,所以我们只是简单做一下了解

    多线程,创建多条线程同时执行任务,这种方式在我们的日常生活中比较常见。但是,在多线程的使用过程中,还有许多需要我们了解的概念。比如,在理解上并行和并发的区别,以及在实际应用的过程中多线程的安全问题,对此,我们需要进行详细的了解。

    并行和并发:在我们看来,都是可以同时执行多种任务,那么,到底他们二者有什么区别呢?

    并发,从宏观方面来说,并发就是同时进行多种时间,实际上,这几种时间,并不是同时进行的,而是交替进行的,而由于CPU的运算速度非常的快,会造成我们的一种错觉,就是在同一时间内进行了多种事情

    而并发,则是真正意义上的同时进行多种事情。这种只可以在多核CPU的基础下完成。

    还有就是多线程的安全问题?为什么会造成多线程的安全问题呢?我们可以想象一下,如果多个线程同时执行一个任务,name意味着他们共享同一种资源,由于线程CPU的资源不一定可以被谁抢占到,这是,第一条线程先抢占到CPU资源,他刚刚进行了第一次操作,而此时第二条线程抢占到了CPU的资源,name,共享资源还来不及发生变化,就同时有两条数据使用了同一条资源,具体请参考多线程买票问题。这个问题我们应该如何解决那?

      有造成问题的原因我们可以看出,这个问题主要的矛盾在于,CPU的使用权抢占和资源的共享发生了冲突,解决时,我们只需要让一条线程战歌了CPU的资源时,阻止第二条线程同时抢占CPU的执行权,在代码中,我们只需要在方法中使用同步代码块即可。在这里,同步代码块不多进行赘述,可以自行了解。

    四,线程池

    又以上介绍我们可以看出,在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。而在Java中,内存资源是及其宝贵的,所以,我们就提出了线程池的概念。

    线程池:Java中开辟出了一种管理线程的概念,这个概念叫做线程池,从概念以及应用场景中,我们可以看出,线程池的好处,就是可以方便的管理线程,也可以减少内存的消耗。

    那么,我们应该如何创建一个线程池那?Java中已经提供了创建线程池的一个类:Executor

    而我们创建时,一般使用它的子类:ThreadPoolExecutor.

    1. public ThreadPoolExecutor(int corePoolSize,  
    2.                               int maximumPoolSize,  
    3.                               long keepAliveTime,  
    4.                               TimeUnit unit,  
    5.                               BlockingQueue<Runnable> workQueue,  
    6.                               ThreadFactory threadFactory,  
    7.                               RejectedExecutionHandler handler)

    这是其中最重要的一个构造方法,这个方法决定了创建出来的线程池的各种属性,下面依靠一张图来更好的理解线程池和这几个参数:


    又图中,我们可以看出,线程池中的corePoolSize就是线程池中的核心线程数量,这几个核心线程,只是在没有用的时候,也不会被回收,maximumPoolSize就是线程池中可以容纳的最大线程的数量,而keepAliveTime,就是线程池中除了核心线程之外的其他的最长可以保留的时间,因为在线程池中,除了核心线程即使在无任务的情况下也不能被清除,其余的都是有存活时间的,意思就是非核心线程可以保留的最长的空闲时间,而util,就是计算这个时间的一个单位,workQueue,就是等待队列,任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出)。threadFactory,就是创建线程的线程工厂,最后一个handler,是一种拒绝策略,我们可以在任务满了知乎,拒绝执行某些任务。

    线程池的执行流程又是怎样的呢?


    有图我们可以看出,任务进来时,首先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,若果有,就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。

    handler的拒绝策略:

    有四种:第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满

                 第二种DisCardPolicy:不执行新任务,也不抛出异常

                 第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行

                 第四种CallerRunsPolicy:直接调用execute来执行当前任务

    五,四种常见的线程池:

    CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。

    SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。

    SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。

    FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程

    展开全文
  • 并发编程经历:线程池的使用

    万次阅读 多人点赞 2019-07-31 18:38:24
    线程池的使用 使用线程池管理线程可以最大程度的利用线程,节省资源消耗,它通过利用已有的线程多次循环执行多个任务从而提高系统的处理能力。 我们可以通过java.util.concurrent.ThreadPoolExecutor类来创建线程池...
  • 线程池

    千次阅读 2018-01-04 15:32:49
    线程池Executor框架  Executor采用工厂模式提供了各种类型的线程池,是实际使用中我们就直接从Executor中获取我们想要的线程池,拿来直接使用即可。下面简单的介绍下Executor提供的五大类线程池。  ...
  • 线程池(ThreadPoolExecutor JDK1.7)

    千次阅读 2016-05-08 15:17:37
    平常我们经常都会使用到线程池,但是有没考虑过为什么需要使用线程池呢?下面我列举一下问题,大家可以思考一下 1.当前服务器的硬件环境是多少核的CPU,它和线程的关系又是什么? 2.jvm能创建多少个线程? 3.多...
  • 10_线程池

    2020-11-14 09:48:29
    使用 线程池 获取 Callable 接口 Callable 接口,是一种让线程执行完成后,[ 能够返回结果的 ] 在说到 Callable 接口的时候,我们不得不提到 Runnable 接口 [ 两种写法 ] /** * 实现Runnable接口 */ class ...
  • 今日科技快讯 ...昨日有消息称:因易到用车在规定的5月底期限内无法解决司机提现问题,司机已经在易到公司的18层里静坐要钱。对此,易到官方回应称将于2017年6月29日全面开放线上提现。...
  • 1、什么是线程池: java.util.concurrent.Executors提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,...
  • 线程池的种类以及使用场景

    千次阅读 2019-05-16 23:52:06
    线程池 线程池的种类以及使用场景 CachedThreadPool 这类线程池的特点就是里面没有核心线程,全是非核心线程,其maximumPoolSize设置为Integer.MAX_VALUE,线程可以无限创建,当线程池中的线程都处于活动状态的...
  • Android与线程池

    千次阅读 2019-03-04 21:49:57
    Android与线程池: 在Android中会经常用非UI线程来处理耗时的逻辑,即使用线程处理异步任务,但每个线程的创建和销毁都需要一定的开销。假设每次执行一个任务都需要开一个新的线程去执行,则这些线程的创建和销毁将...
  • Java 五种线程池详解、更加优雅的管理线程

    万次阅读 多人点赞 2019-06-11 00:15:01
    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主威威喵原创,请多支持与指教。 ... 在应用开发中,通常有这样的需求,就是并发下载文件操作,比如百度网盘下载文件、腾讯视频下载视频等...
  • Java多线程-线程池ThreadPoolExecutor构造方法和规则

    万次阅读 多人点赞 2017-05-03 17:15:37
    为什么用线程池博客地址 http://blog.csdn.net/qq_25806863原文地址 http://blog.csdn.net/qq_25806863/article/details/71126867有时候,系统需要处理非常多的执行时间很短的请求,如果每一个请求都开启一个新线程...
  • java 创建线程的三种方式、创建线程池的四种方式

    万次阅读 多人点赞 2019-02-23 21:01:44
    概要: java创建线程的三种方式: 继承Thread类创建线程类 ... newCachedThreadPool 创建一个可缓存的线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程 newFixedThread...
  • JAVA多线程线程池

    千次阅读 2019-08-25 11:06:12
    目录 1、线程状态 (1) 新建状态 (2) 就绪状态 (3) 运行状态 (4) 阻塞状态 (5) 死亡状态 2、线程优先级 3、同步工具synchronized、wait、...4、创建线程 ...(3) 通过 Callable 和 Future 创建线程 ...6、线程池 (...
  • Java多线程 - 线程池

    千次阅读 2018-06-17 00:04:27
    在我们开发中经常会使用到多线程,比如在Android中,网络请求或一些耗时操作必须放在子线程中运行,往往会通过Thread开启一个子线程去执行...所以java提供了线程池来管理我们创建的线程线程池的优势: 1. 降低...
  • 线程池详解---线程复用、线程销毁

    千次阅读 2019-10-05 16:27:46
    本文是基于jdk1.6对线程池(ThreadPoolExecutor)进行线程池执行Runnable任务主过程的剖析,jdk1.8及更高版本基本原理与1.6类似,但1.6主流程简单,没有进行太多优化,易于学习。 在这里我们需要知道一些基本的常识...
  • java线程间通信、线程池

    千次阅读 2019-08-22 19:38:34
    文章目录第四章:线程状态4.1 线程状态概述4.2 Waiting (无限等待)和线程间通信4.3 线程间通信代码实战第五章:线程池5.1 线程池5.2 线程池的使用 第四章:线程状态 4.1 线程状态概述 当线程被创建并启动以后,它既...
  • 线程池线程复用原理 文章目录线程池线程复用原理前言项目环境1.什么是线程复用?2.线程复用的原理3.线程池执行流程3.1 流程图3.2 线程创建的流程3.3 ThreadPoolExecutor#execute 源码分析3.4 逐行分析4.线程复用...
  • 线程池是如何重复利用空闲的线程来执行任务的?

    千次阅读 多人点赞 2019-03-29 15:18:55
    在Java开发中,经常需要创建线程去执行一些任务,实现起来也非常方便,但如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和...
  • 高并发:线程线程锁与线程池(精华)

    千次阅读 多人点赞 2019-04-18 19:44:24
    线程——多线程的开启——线程锁——线程同步工具——手写连接池——连接池工具类。 一、线程 1.线程的概念 2.线程与进程的关系 3.定义: 区别:如上!!! 4.wait()和sleep() 5.线程的状态及其他...
  • 线程池ExecutorService空闲线程的个数

    万次阅读 2018-06-28 20:02:33
    默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,...
  • java多线程并发及线程池

    万次阅读 2016-11-23 17:04:07
    线程的常用创建方式 1、继承Thread类创建线程类 public class FirstThreadTest extends Thread { public void run(){ System.out.println("这里是线程的执行方法"); } public static void main(String[] ...
  • 线程基础:线程池(5)——基本使用(上)

    万次阅读 多人点赞 2016-01-23 10:02:49
    第一篇文章,我将讲解JAVA原生线程池的基本使用,并由此延伸出JAVA中和线程管理相关的类结构体系,然后我们详细描述JAVA原生线程池的结构和工作方式;第二篇文章,我们将继续深入,讲解JAVA原生线程池的高级特性,...
  • 线程的创建与线程池ThreadPoolExecutor,Executors

    万次阅读 多人点赞 2018-07-31 17:42:25
    线程的创建与线程池线程池工具类 1.线程的创建方式 1.1继承Thread类重写run方法 public class Test { public static void main(String[] args) { Thread thread = new MyThread(); thread.setName(...
  • Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-线程本地ThreadLocal的介绍与使用 Java多线程编程-(4)-线程间通信...
  • 线程、多线程线程池总结

    千次阅读 2016-07-21 14:08:18
    先看几个概念: 线程:进程中负责程序执行的执行单元。一个进程中至少有一个线程...线程池:基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。
  • Java线程池中的核心线程是如何被重复利用的?

    千次阅读 多人点赞 2018-03-15 17:44:07
    Java线程池中的核心线程是如何被重复利用的?引言在Java开发中,经常需要创建线程去执行一些任务,实现起来也非常方便,但如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建...
  • Java 多线程与并发——线程池

    万次阅读 多人点赞 2016-07-09 16:20:52
    使用线程池可以降低资源消耗,提高线程的可管理性。生产环境中不建议使用 Executors 的静态方法创建线程池,建议根据业务自定义 ThreadPoolExecutor 。LinkedBlockingQueue 一定需要指定大小,因为 ...

空空如也

1 2 3 4 5 ... 20
收藏数 2,559,349
精华内容 1,023,739
关键字:

线程池