一、线程池





线程池的一些参数:

corePoolSize:核心线程数量
maximumPoolSize:核心线程数量+临时线程数量
上述是"java 的线程池策略"(其他语言,其他库的线程池可能不同)
keepAliveTime :临时线程的存活时间.临时线程允许摸鱼的最大时间
Timeunit:时间单位:秒/分钟/毫秒...
workQueue:线程池要完成的任务队列,每个任务都是通过Runnable来进行描述的
线程池在使用的时候,首先会创建一些线程,然后需要调用者给线程池放一些任务,这些线程就会从队列中取出任务,并且执行里面的代码。
(*工厂设计模式:正常创建一个对象是通过构造方法,new出来的。但是构造方法存在一定缺陷的,工厂模式就用来填补上这样的缺陷。不用构造方法来出池化对象,通过一组静态方法来初始化对象,静态方法就可以起不同的名字来做区分了。)
ThreadFactory:线程工厂 这个类就是Thread类的工厂类,由于在线程池中,是需要创建很多线程的,创建出来的线程需要进行哪些初始化操作?就可以通过threadFactory来进行设定。
实际上就是通过newThread方法,针对Thread对象进行初始化,再把这个Thread对象返回出来。比如想把线程池中的线程,按照一定的规则,设置name,或者想把线程池的线程全都设置成后台线程,或者都设置xxx为优先级。
例如,我想要将笛卡尔坐标系下的点转化为极坐标下的点表示,那么------

然而,多个版本的构造方法,需要"重载",而重载要求方法名称相同但是参数列表不能相同,这里的参数列表相同,因此无法构成重载。那么此时的解决方法也就是:

这就是用来构造Point对象的类,也被称为"工厂类"
RejectedExecutionHandler:拒绝策略
线程池,有任务列表、阻塞队列,当任务队列满了的时候,如果再次添加新的任务,会发生什么呢?
正常来说,除非特殊说明,我们写的代码是不希望有这种突发性的阻塞的,因为这种阻塞稍不留神可能就对程序造成不可预估的影响。
因此直接让添加任务的线程阻塞,其实是不太好的,不太好就意味着要有其他的方法------因此标准库的线程池就引入了"拒绝策略"

正常情况下,是线程池里面的线程执行任务的,但是现在线程池里面的线程忙不过来了,就只能由调用者自己找个线程来执行任务
标准库中提供了一个对ThreadPoolExecutor进行了封装的简化版本Executors,本质上也是工厂类,提供了一些工厂方法,对上述的ThreadPoolExecutor进行不同的初始化。

这里的工厂方法,就是在创建不同风格的线程池。
java
package Thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class demo39 {
public static void main(String[] args) {
//固定线程数目的线程池,核心线程数和最大线程数都是4
ExecutorService executorService = Executors.newFixedThreadPool(4);
//核心线程数设置为0,最大线程数设为一个Int最大值这样的线程池
ExecutorService executorService1 = Executors.newCachedThreadPool();
//固定只有一个线程的线程池(这个东西确实用的不多,可以通过这种方式来代替创建线程的方式)
ExecutorService executorService2 = Executors.newSingleThreadExecutor();
//这个线程池,本质上是一个定时器,放到这个线程池中的任务,会在一定时间之后执行
ExecutorService executorService3 = Executors.newScheduledThreadPool(4);
}
}

现在我们来让这个线程池来执行一些任务,为了更清晰地看出这个任务做了10次,我们来对i进行打印。然而这里不能直接这么些,会出现"变量捕获"的问题。

这里通过这种方法来进行解决。

有些公司更加想要完全体的ThreadPoolExecutor,可控性更强。

如果队列中没有其他的任务,take就会阻塞,一直阻塞到其他线程执行submit为止
javascript
package Thread;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
class MyFixedThreadPool{ // 固定线程池。
private BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<Runnable>(); // 阻塞队列,用于存放任务。
public MyFixedThreadPool(int n){ // 构造方法,初始化线程池。
for(int i = 0; i < n; i++){ // 创建n个线程。
Thread t = new Thread(()->{ // 创建线程。
try {
while (true) {
Runnable task = blockingQueue.take(); // 从阻塞队列中取出任务。
task.run(); // 执行任务。
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
});
t.start();
}
}
public void submit(Runnable task) throws Exception{ // 提交任务。
// 1. 将任务放入阻塞队列。
blockingQueue.put(task);
}
}
public class demo40 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
MyFixedThreadPool myFixedThreadPool = new MyFixedThreadPool(100); // 创建线程池。
for(int i = 0; i < 10; i++){ // 提交1000个任务。
int finalI = i; // 闭包。
myFixedThreadPool.submit(()->{ // 提交任务。
System.out.println("任务" + finalI + "正在执行"); // 打印任务正在执行。
});
}
}
}

二、定时器
定时器在java编程中是一个非常终于熬的组件。
阻塞队列,太重要了,太常用了,在实际工作中,会把阻塞队列单独封装成一个/一组服务器
定时器也是类似,也会被单独封装成一个/一组服务器,类似于闹钟。
为什么需要定时器呢?------编程中有些任务,不需要立即执行,而是要等一会儿,等到到一定时间的时候再去执行。
Java标准库提供了Timer这样的类,可以通过他来实现简单的定时器。

一开始输出:程序启动,过了4s之后输出"定时器执行任务"
自行实现一个定时器
java
package Thread;
import java.util.PriorityQueue;
class MyTimerTask implements Comparable<MyTimerTask>{
private Runnable task;
private long delay;
private long time ;
public MyTimerTask(Runnable task, long delay){
this.task = task;
this.time = delay + System.currentTimeMillis();
}
public Runnable getTask(){
return task;
}
public long getTime(){
return time;
}
public int compareTo(MyTimerTask o){ // 比较两个任务的时间,谁的时间小谁排在前面。
return (int)(this.time - o.time); // 比较两个任务的时间,谁的时间小谁排在前面。
} // 比较两个任务的时间,谁的时间小谁排在前面。
}
//自己实现定时器
//定时器能够同时管理多个任务
//有一定的数据结构来组织这多个任务
//ArrayList不太合适
//更好的选择是优先级队列
class MyTimer{
private PriorityQueue<MyTimerTask> queue = new PriorityQueue<MyTimerTask>();
private static Object locker = new Object();
public MyTimer(){
//创建线程
Thread t = new Thread(()->{ // 线程的任务是不断地从队列中取出任务,并执行。
while (true) {
try { // 捕获异常。
synchronized(locker){ // 出队列。
if(queue.isEmpty()){
locker.wait();
}
MyTimerTask task = queue.peek(); // 取出队列中的第一个任务。
long curTime = System.currentTimeMillis(); // 获取当前时间。
if(curTime < task.getTime()){ // 如果当前时间小于任务的时间,说明任务还没有到执行时间。
locker.wait(task.getTime() - curTime);
}else{
queue.poll(); // 取出队列中的第一个任务。
task.getTask().run(); // 执行任务。
}
}
} catch (InterruptedException e) { // 捕获异常。
e.printStackTrace(); // 打印异常栈。
}
}
});
t.start(); // 启动线程。
}
public void schedule(Runnable task, long delay){
synchronized(locker){ // 入队列。
queue.offer(new MyTimerTask(task, delay)); // 入队列。
locker.notify(); // 唤醒线程。
} // 入队列。
}
}
public class demo42 {
public static void main(String[] args) {
MyTimer timer = new MyTimer(); // 创建定时器。
timer.schedule(new Runnable() {
@Override
public void run() { // 任务的执行逻辑。
System.out.println("定时任务 3000"); // 打印出 hello world。
}
}, 3000);
timer.schedule(new Runnable() {
@Override
public void run() { // 任务的执行逻辑。
System.out.println("定时任务 2000"); // 打印出 hello world。
}
}, 2000); timer.schedule(new Runnable() {
@Override
public void run() { // 任务的执行逻辑。
System.out.println("定时任务 1000"); // 打印出 hello world。
}
}, 1000);
}
}