线程池

线程池

一,java线程的理解

一,线程模型分类:

1.用户级别线程(User-level Thread ULT)

​ 用户程序实现,不依赖操作系统核心,应用提供创建,同步,调度和管理线程的函数来控制用户线程,不需要用户态/内核态切换,速度块内核对ULT无感知,线程阻塞则进程(包括它的所有线程)阻塞

​ ----用户级线程是由进程创建的线程,由进程来调度,按照顺序一个一个的进行,一个线程阻塞,那么它的队列就执行不下去,就会阻塞进程

2.内核级线程(Kernel-Level Thread KLT)

​ 系统内核管理线程,内核保存线程的状态和上下文信息,线程阻塞不会引起进程阻塞,在多处理器气系统上,多线程在多处理器上并行运行。线程的创建,调度和管理由内核完成,效率比ULT要慢,比进快程操作快。

用户级别线程和内核级线程的关系

内核级线程会存储在内核空间能够直接操作cpu,用户级别线程存在于用户空间,需要通过提供交互的接口而通过内核空间进行操作cpu,这是一种安全设置机制
在这里插入图片描述

例:

str="my string"  //存在于用户空间
x=x+2
file.write(str)//切换到内核空间
y+x+4//切换回用户空间

Java线程与系统内核线程

Java线程创建是依赖于系统内核,通过JVM调用系统库创建内核线程,内核线程与Java-Thread是1:1的映射关系
在这里插入图片描述

二,使用线程池的优势:

线程调度cpu运行,操作系统是按照时间片的轮询,当一个线程的时间片用完,但是任务没有处理完,就会保存相应的状态信息,这个保存在内核空间的Tss任务段这里,等重新一轮的时间片过来,这个线程就要重新加载保存在内核空间中的这些信息,会涉及到用户空间和内核空间的转换,当处理高并发问题时,这种转换还有线程的创建和销毁都是重量级的操作,所以会拖慢效率,使用线程池就可以解决这些问题

如图所示:
在这里插入图片描述

线程池的意义:

线程是稀缺资源,它的创建与销毁是比较重且耗资源的操作,而java线程依赖于内核线程,创建线程需要进行操作系统状态的切换,为避免资源过度消耗需要设法重用线程执行多个任务,线程池就是一个线程缓存,负责对线程统一分配,调优与监控

线程池的优势:

1.重用存在的线程,减少线程创建,消亡的开销,提高性能

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

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

三,线程池的五种状态:

Running:能接收新任务,以及处理已经添加的任务

Shutdown:不接收新任务,可以处理已经添加的任务

Stop:不接收新任务,不处理已经添加的任务,并且中断正在处理的任务

Tidying:所有任务已经终止,ctl记录的任务数量为0(tcl负责记录线程池的运行状态与活动线程数)

Terminated:线程池彻底终止,则线程池转化为terminated状态

状态转换图:
在这里插入图片描述

二,线程池的的源码:

一,executor框架
在这里插入图片描述

executor:是一个接口,里面只有一个执行的方法

executorService:一个子接口,里面定义了线程池的各个状态

一,线程池的创建方式:

executors:线程池的一个工具类,工具类有五种创建线程的方法:

1.newScheduledThreadPool()

​ 实现定时和周期性任务的线程池,corePoolSize是传进来的固定值,maximumPoolSize无限大,当执行scheduleAtFixedRate或者scheduleWithFixedDelay方法时,会向DelayedWorkQueue添加一个实现RunnableScheduledFuture接口的ScheduledFutureTask(任务的包装类),并会检查运行的线程是否达到corePoolSize。当执行完任务后,会将ScheduledFutureTask中的time变量改为下次要执行的时间并放回到DelayedWorkQueue中。

2.newCachedThreadPool()

​ 根据需要创建线程的线程池,orePoolSize是0,maximumPoolSize是Int的最大值,队列是阻塞队列SynchronousQueue,这个队列没有缓冲区,所以其中最多只能存在一个元素,有新的任务则阻塞等待

3.newFixedThreadPool()

​ 可重用固定线程数的线程池,超出的线程会在队列中等待,只有固定数量的核心线程,不存在非核心线程,任务队列采用的是LinkedBlockingQueue。

4.newSingleThreadPool()

​ 使用单个线程工作的线程池,该线程池才用链表阻塞队列LinkedBlockingQueue,先进先出原则,所以保证了任务的按顺序逐一进行

5.newWorkStealingPool()

例:

ExecutorService pool=Executors.newFixedThreadPool(5)//一池五个处理线程
ExecutorService pool=Executors.newSingleThreadPool()//一池一个处理线程
ExecutorService pool=Executors.newCachedThreadPool()//一池N个处理线程
ExecutorService pool=Executors.newScheduledThreadPool(int n)//时间表
ExecutorService pool=Executors.newWorkStealingPool()//jdk1.8出现的新特性,可以窃取任务,缓解线程的饥饿

executors的五种创建方式,里面的队列的最大值(Integer.Max_Values),任务会一直堆积,造成OOM的情况,所以,不推荐使用executors的创建方式

创建线程池的类ThreadPoolExecutor的类型图
在这里插入图片描述

必须手动的创建线程池:

final ExecutorService pool=new ThreadPoolExecutor(2,3,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runable>(5)),Executor.defaultThreadFactory());
try{
	for(int i=0;i<9;i++){
		pool.execute(new Task(i));//Task实现了Runnable/Collable接口,在这个类里面执行run方法执行真正的任务
	}
}
catch(..){
..
}
finally{
	pool.shutdown();
}

二,参数介绍:

int corePoolSize:核心线程数

​ 在创建完线程池之后,核心线程先不创建,在接到任务之后创建核心线程。并且会一直存在于线程池中,数量一般情况下设置为CPU核数的二倍即可。

int maximumPoolSize:最大线程数

​ 核心线程都被占用,但还有任务要做,就创建非核心

long keepAliveTime: 非临时线程存活的时间

TimeUnit unit: 时间的单位(一个枚举类型)

BlockingQueue< Runnable> workQueue: 任务队列

​ 任务进来之后先分配给核心线程执行,核心线程如果都被占用,并不会立刻开启非核心线程执行任务,而是将任务插入任务队列等待执行,核心线程会从任务队列取任务来执行,任务队列可以设置最大值,一旦插入的任务足够多,达到最大值,才会创建非核心线程执行任务。

​ 有四种:

​ (1)SynchronousQueue:这个队列接收到任务会直接提交给线程处理,而不保留它,如果线程都在工作就新建一个线程来处理这个任务,所以使用这个类型队列的时候:maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大

​ (2)LinkedBlockingQueue:队列没有最大值限定,所以接收到任务时,新建线程处理,如果核心线程数等于核心线程数上限,则进入队列等待

​ (3)ArrayBlockingQueue:限定队列的长度,如果总线程数到maxmumPoolSize,并且队列也满了,会发生错误,或执行定义好的饱和策略

​ (4)DelayedWorkQueue:队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

ThreadFactory threadFactory:线程工厂

​ 用线程工厂给每个创建出来的线程设置名字,一般无需设置

RejectedExecutionHandler handler:拒绝策略

jdk提供了四种),可以自定义,只要实现这个接口

​ (1)AbortPolicy(){丢弃一个任务//会抛出一个异常} 默认

​ (2)DiscardPolicy(){直接丢弃一个任务}

​ (3)DiscardOldestPolicy(){会丢弃队列最前面的一个任务,重新尝试调用这个任务。一直重复}

​ (4)CallerRunPolicy(){当线程爆满时,将任务返回给任务的调用者由它去执行,即用调用者所在的线程来处理任务。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度}

三,线程的执行流程:

在这里插入图片描述

关键源码:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值