线程池
线程池:创建一堆线程重复利用。
自定义线程池:
结构如下:
Blocking queue:5个变量3个方法
take:
put:
Size:
带超时的阻塞获取:
线程池的代码:
执行任务的操作:
带超时时间的阻塞添加
ThreadPoolExecutor
ThreadPoolExecutor的构造方法:
34是决定救急线程的
jdk提供的拒绝策略
当线程数大于到达maximumpoolsize后仍然有新任务。
根据这个构造方法,JDK executor类提供众多工厂方法来创建各种用途的线程池。
1 固定大小的线程池
固定大小线程池的实现:
大小是2,有三个任务
没有任务了之后也不会主动结束。
第二个参数是线程工厂,可以给线程改名字,如上所示:
2 带缓冲功能的线程池
意思是取走了后才能放东西,take后才能put
3 单线程线程池
就算线程执行失败,他还重新创造线程来执行别的任务。
提交任务
submit
pool.submit()提交任务后,主线程不会等待 Lambda 表达式中的任务执行完(包括休眠的 1000 毫秒 ),而是继续往下执行Log.debug("{}", future.get())这行代码。而future.get()方法会阻塞主线程,直到任务执行完毕并返回结果,这样就实现了任务的异步执行,同时又能获取执行结果。
任务调度线程池ScheduledThreadPoolExecutor
任务调度线程池之前用java.util.timer来实现定时功能。
timer的缺点:所有的任务由一个线程来调度,串行执行,如果一个任务延迟或者出现了异常会影响其他任务的执行。
ScheduledThreadPoolExecutor可以延时执行任务,而且可以弥补上述缺点,需要设置不同的线程数量。
定时执行任务:scheduleAtFixedRate()period参数设定是多久执行一次任务
scheduleWithFixedDelay()TimeUnit参数设定的是任务与任务之间的间隔时间是多少。
正确处理线程池异常:
第一种方法是主动加try catch块,第二种方法是用callable,future可以或者任务执行过程中的异常。
Callable 的 call 方法可以有返回值并且可以抛出异常。而 Future 用于获取 Callable 任务的执行结果,也可以通过 Future 的 get () 方法获取任务执行过程中抛出的异常。如果任务执行过程中抛出异常,在调用 Future 的 get () 方法时,这个异常会被重新抛出,可以在调用处进行捕获和处理。
线程池的应用:让每周四的18:00:00定时执行任务
Tomcat线程池
连接器部分用到了线程池。
- LimitLatch 用来限流,可以控制最大连接个数,类似 J.U.C 中的 Semaphore 后面再讲
- Acceptor 只负责【接收新的 socket 连接】
- Poller 只负责监听 socket channel 是否有【可读的 I/O 事件】
- 一旦可读,封装一个任务对象(socketProcessor),提交给 Executor 线程池处理
- Executor 线程池中的工作线程最终负责【处理请求】
J.U.C
AQS (AbstractQueuedSynchronizer)
阻塞式锁和相关的同步器工具的框架
独占锁要重写tryAcquire、tryRelease、isHeldExclusively方法
重写tryAcquire方法。
ReentrantLock
默认为非公平锁实现
非公平锁实现原理:CAS操作成功该线程就直接获得锁,锁被释放的时候也是公平竞争锁。
可重入的原理:state0-1是获得了锁,可重入就是state可以继续加,当该线程再次获取同一把锁时,检查当前持有锁的线程是否为自己,直到state为0的时候才释放锁。
可打断的原理
公平锁:
条件变量await
条件变量signal