线程池(ThreadPoolExecutor)
前面谈到创建销毁进程太消耗资源而引入了线程,而频繁的创建和销毁线程就失去了线程轻量化的特点,而无法忽视线程的创建和销毁,所以进一步优化就得到了线程池这个概念。
提前将线程准备好,放进一个“池”(数据结构)中,当需要时就去池中申请,用完后就放回池中。
线程池的实现
线程池在Java标准库中就有具体的实现:ThreadPoolExecutor。
创建这个类就需要填写一些参数,当线程池创建好了以后往里面放任务才会开始创建线程。
ThreadPoolExecutor的构造方法
1)第一个参数corePoolSize表示核心线程数+临时线程数,第二个参数maximumPoolsize表示线程总数。
在Java中创建一个线程时,一创建就申请的就是核心线程,当核心线程忙不过来时,线程池就会申请一些临时线程来帮忙等到不忙时就会销毁这些临时线程,核心线程不会被释放。
当核心线程不等于线程总数时,总数-核心=临时,总数=核心线程数就没有临时线程了。
2)keepAliveTime表示临时线程的最大存活单位,后面的 TimeUnit unit表示时间单位(分钟,秒....)
3)workQueue表示要执行的任务队列,每个任务都是通过Runnable表示的。
当线程池使用时就会创建一些线程,然后调用者将一些任务放入队列,线程就会去队列中取出任务进行执行。
4)ThreadFactory线程工厂,工厂设计模式。
正常创建一个线程对象时,一般是new出来的,但是构造方法也会有缺陷,工厂模式就可以填补这样的缺陷。
当我们这样使用构造方法时,就会报错,所以我们就可以使用一组静态方法进行初始化,而这样的静态方法存在的类叫做工厂类。
通过工厂类的方法就可以完成初始化。
而ThreadFactory就是Thread的工厂类,我们可以通过一个类实现ThreadFactor这个接口来实现对线程的初始化。
5)RejectedExecutionHandler 拒绝策略
当阻塞队列任务满了再去添加任务时,此时就会阻塞,但是有时阻塞会对程序造成不可预估的影响,所以引入了拒绝策略。
RejectedExecutionHandler这个参数并不需要我们自己创建一个类传进去,而是标准库中有四个已经实现的类,我们只要把这几个类传进去需要的就行了。
第一个是直接终止,并抛出异常。
第二个是调用者自己负责执行。
第三个是抛弃最老的任务。
第四个是抛弃最新的任务。
Java中将ThreadPoolExecutor进行了封装,封装成了Executor这个工具类,通过这个类我们可以创建不同风格个线程池,Executors是一个工具类 里面是提供了创建线程池的多个方法,通过submit方法将任务添加到任务队列。
模拟实现线程池
class MyBlockQueuePool{
BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>(100);
public MyBlockQueuePool(int n) throws InterruptedException {
for (int i = 0; i < n; i++) {
Thread thread = new Thread(()->{//创建四个线程,每个线程都去队列中循环拿取
while (true) {
try {
Runnable a = blockingQueue.take();
a.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
public void submit(Runnable a) throws InterruptedException {
blockingQueue.put(a);
}
}
public class dome14 {
public static void main(String[] args) throws InterruptedException {
MyBlockQueuePool myBlockQueue = new MyBlockQueuePool(4);
for (int i = 0; i < 100; i++) {
int id = i;
myBlockQueue.submit(()->{
System.out.println("执行任务"+id);
});
}
}
}
定时器
阻塞队列非常重要,在实际工作中常常要将其封装成一组/一个服务器。
而定时器往往也要做此操作。
定时器在Java中也有实际实现。
模拟实现定时器
class struct implements Comparable<struct> {
public Runnable runnable = null;
public long time;
public struct(Runnable runnable,long time) {
this.runnable = runnable;
this.time = System.currentTimeMillis()+time;
}
public long getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
@Override
public int compareTo(struct o) {
return (int) (this.time - o.time);
}
}
class MyTime{
PriorityQueue <struct> structs = new PriorityQueue<>();
Object object = new Object();
public MyTime (){
Thread thread = new Thread(()->{
while (true) {
synchronized (object) {
if (structs.isEmpty()) {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
struct a = structs.peek();
long curtime = System.currentTimeMillis();
if (a.getTime() > curtime) {
try {
object.wait(a.getTime()-curtime);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
a.runnable.run();
structs.poll();
}
}
}
});
thread.start();
}
public void submit(Runnable runnable ,long time){
synchronized (object) {
structs.offer(new struct(runnable, time));
object.notify();
}
}
}
public class dome16 {
public static void main(String[] args) {
MyTime n = new MyTime();
n.submit(()->{
System.out.println("haha");
},3000);
n.submit(()->{
System.out.println("haha");
},2000);
n.submit(()->{
System.out.println("haha");
},1000);
}
}