java线程池

线程池的一些解释文字
    一:使用线程池的好处:
 1、使用线程池可以重复利用已有的线程继续执行任务,避免线程在创建和销毁时造成的消耗
2、由于没有线程创建和销毁时的消耗,可以提高系统响应速度
3、通过线程可以对线程进行合理的管理,根据系统的承受能力调整可运行线程数量的大小等
    二、如何使用线程池(Executors是所有线程池的顶级父类)
1.创建线程池对象(使用 Executors关键字来调用相应的线程方法)
2.提交任务
3.关闭线程池(使用 shutdown)
    三:线程池的一些关键字的意思
1.corePoolSize:核心线程数
2.maximumPoolSize:线程池最大容纳线程数
3.keepAliveTime:空闲线程的存活时间
4.unti:时间单位,为KeepAliveTime指定时间单位
5.workQueue:阻塞队列,用于保存任务的阻塞队列
6.threadFactory:创建线程的工程类
7.handler:饱和政策(拒绝策略)

线程池的分类
    ThreadPoolExcecutor
        newCachedThreadPool
            创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时会重用它们,并在需要的时候使用提供的ThreadFactory创建新线程
特征:
1.线程池中数量没有固定,可达到最大值(Integer.MAX_VALUE)
2.线程池中的线程可进行缓存和重复利用和回收(回收默认时间为1分钟)
3.当线程池中,没有可使用的线程时,会创建一个线程
        newFixedThreadPool
            创建一个可重用固定线程数的线程池,已共享的无界队列方式来进行运行这些线程。在任意点,在大多数nThread线程会处于处理任务的活动状态。如果所有线程处于活动状态的时候提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭之前的执行期间由于失败而导致的任何线程终止,那么一个新线程将代替他执行后续的任务,在某个线程被显示的关闭之前,池中的线程将一直存在。
特征:
1.线程池中的线程存在一定的量,可以很好的控制线程的并发量
2.线程可以被重复使用,在显示关闭之前,都将一直存在
3.超出一定量的线程被提交时候需在队列中等待
        newSingleThreadExecutor
            创建一个使用单个worker线程的Executor,以无界方式来运行该线程。
注意:如果因为在关闭之前的执行期间出现失败而终止了此个单个线程,那么如果需要,一个新线程将替代它执行后续任务。可保证顺序的执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的newFixedPool不同,可保证无序重新配置此方法返回的执行程序即可使用其他线程
特征:线程池中最多执行一个线程,之后的线程活动将会排在执行队列中以此执行
    ScheduledThreadPoolExecutor
        newSingleThreadScheduledExecutor
            创建一个单线程的执行程序,它可安排在给定延迟后运行命令或者定期地执行;
特征:
(1)线程池中最多执行一个线程,之后提交的线程活动将会排在队列中以此执行
(2)可定时或者延迟执行线程 活动
        newScheduledThreadPool
            创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行
特征:
(1)线程池中具有指定数量的线程,几遍是空线程也将保留
(2)可定时或者延迟执行线程活动
    ForkJoinPool
        newWorkStealingPool
            创建一个带并行级别的线程池,并行级别决定了同一时刻最多有多少个线程在执行,如不传入执行级别参数,将默认为当前系统的CPU个数

线程池的工作原理
    1.首先判断线程池中的核心线程池是否都在执行任务,如果没有就创建一个新的线程执行刚提交的任务,如果核心线程池的线程都在执行任务,那么就执行第二步
2.判断当前阻塞对列是否已满,如果没满,就将任务存储到阻塞队列中,否则就执行第三步
3.判断线程池是否已满,也就是线程池的最大线程数是否已满,如果未满就创建线程执行任务,否则就按照饱和策略进行处理

图解:

java线程池_第1张图片

 饱和政策的分类
    1.ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出
RejectedExecutionException异常。 ▪ 2.ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛
出异常。
 ▪ 3.ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的
任务,然后重新尝试执行任务(重复此过程) ▪ 4.ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

阻塞队列的分类
    BlockingQueue
        ArrayBlockingQueue
            基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长的数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列,除了一个定长的数组外,ArrayBlockingQueue内部还保存着两个整型变量,分别表示这队列的头部和尾部在数组中的位置。
ArrayBlockingQueue在生产者放入数据和消费者获取数据,都是公用同一个锁对象,由此也意味着 两者无法真正的并行运行,这点尤其不同于LikedBlockingQueue;
        LikedBlockingQueue
            基于链表的阻塞队列,同ArrayListBlockingQueue类似,其内部也维持着一个数据缓冲队列(该队列由一个链表构成),当生产者往队列中放入一个数据时,队列会从生产者手中获取数据,并缓存在队列内部,而生产者立即返回;只有当队列缓冲区达到最大值缓存容量时(LikedBlockingQueue可以通过构造函数指定该值),才会阻塞生产队列,直到消费者从队列中消费一部分数据时,生产者线程才会被唤醒,反之对于消费者这段的处理也是基于同样的原理;
而LikedBlockingQueue之所以能够高效的处理并发数据,还因为其对于生产者端和消费者端分别采用了独立的锁来控制数据同步,这就意味着在高并发的情况下生产者和消费者可以并行操作队列中的数据,以此提高整个队列的并发性能
        DelayQueue
            DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue是一个没有大小限制的队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞
使用场景:
使用场景较少,常见的例子比如使用DelayQueue来管理一个超时未响应的连接队列
        PriorityKingQueue
            基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象来决定),但需要注意的是PriorityBlockingQueue并不会阻塞数据生产者,而只会在没有可消费的数据的时候,阻塞数据的消费者。因此使用的时候要特别注意,生产者的生产数据的速度绝对不能快于消费者消费数据的速度,否则将会耗尽所有堆内存空间在实现PriorityBlockingQueue时,内部控制线程同步的锁采用的是公平锁
        SynchronousQueue
            一种无缓冲的等待队列,类似于无中介的直接交易,有点像原始社会中的生产者和消费者,生产者拿着产品去集市销售给产品的最终消费者,而消费者必须亲自去集市找到所要商品的直接生产者,如果一方没有找到合适的目标,那么对不起大家都在集市等待。相对于有缓冲的BlockingQueue来说,少了一个中间经销商的环节(缓冲区),如果有经销商,生产者直接把产品批发给经销商,而无需在意经销商最终会将这些产品卖给那些消费者,由于经销商可以库存一部分商品,因此相对于直接交易模式,总体来说采用中间经销商的模式会吞叶量高一些(可以批量买卖);但另一方面,又因为经销商的引入,使得产品从生产者到消费者中间增加了额外的交易环节,单个产品的及时响应性能可能会降低。
声明一个SynchronousQueue有两种不同的方式,它们之间有着不太一样的行为。公平模式和非公平模式的区别
如果采用公平模式:SynchronousQueue会采用公平锁,并配合一个FIFO队列来阻塞多余的生产者和消费者,从而体系整体的公平策略:
但如果是非公平模式(SynchronousQueue默认):SynchronousQueue采用非公平锁,同时配合一个LIFO队列来管理多余的生产者和消费者,而后一种模式,如果生产者和消费者的处理速度有差距,则很容易出现饥渴的情况,即可能有某些生产者或者是消费者的数据永远都得不到处理,

线程池的生命周期
    (它只有两个运行状态)
RUNNUNG:能接受新提交的任务,并且也能处理阻塞队列中的任务------》
有两种路可以走---》1。调用shutdown()方法,进入SHUTDOWN关闭状态,不在接收新提交的任务,但是会将正在执行的任务执行完毕,也会处理阻塞队列中的已保存的任务
-----》2.调用shutdownNow()方法进入STOP状态,不接受新任务,也不处理队列的任务,也可能会终止正在处理任务的线程
----》不管进入那种状态后最后都会终止进入TIDYING中调用terminated() 方法进入TERMINATED 状态然后终止

图解:

java线程池_第2张图片
【PS:线程池生命周期的图在CSDN线程中,笔记本上也有】

 代码演示:

package thread_pool;

public class MyTask implements Runnable {
    @Override
    public void run() {
        System.out.println( Thread.currentThread().getName()+"=====running!");
    }
}
package thread_pool;


import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class newCachedThreadPoolDemo {
    public static void main(String[] args) {
        //创建线程池对象
        ExecutorService executorService = Executors.newCachedThreadPool();
        //提交任务
        for (int i = 0; i <200 ; i++) {
            executorService.execute(new MyTask());
        }
        //关闭线程池
        executorService.shutdown();

    }
}
package thread_pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class newFixedThreadPoolDemo {
    public static void main(String[] args) {
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //提交任务
        for (int i = 0; i <20; i++) {
            executorService.execute(new MyTask());
        }
        //关闭线程池
        executorService.shutdown();

    }
}

你可能感兴趣的:(初学必备,java,p2p,开发语言)