定时器
java标椎库中的定时器:java.util.Timer
核心方法就一个, schedule(安排),参数有两个:任务是啥,多长时间之后执行
手动实现一个简化版
// 创建一个类, 表示一个任务.
class MyTask implements Comparable<MyTask> {
// 任务具体要干啥
private Runnable runnable;
// 任务具体啥时候干. 保存任务要执行的毫秒级时间戳
private long time;
// after 是一个时间间隔. 不是绝对的时间戳的值
public MyTask(Runnable runnable, long delay) {
this.runnable = runnable;
this.time = System.currentTimeMillis() + delay;
}
public void run() {
runnable.run();
}
public long getTime() {
return time;
}
@Override
public int compareTo(MyTask o) {
// 到底是谁见谁, 才是一个时间小的在前? 需要咱们背下来.
return (int) (this.time - o.time);
}
}
class MyTimer {
// 定时器内部要能够存放多个任务
private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
public void schedule(Runnable runnable, long delay) {
MyTask task = new MyTask(runnable, delay);
queue.put(task);
// 每次任务插入成功之后, 都唤醒一下扫描线程, 让线程重新检查一下队首的任务看是否时间到要执行~~
synchronized (locker) {
locker.notify();
}
}
private Object locker = new Object();
public MyTimer() {
Thread t = new Thread(() -> {
while (true) {
try {
// 先取出队首元素
MyTask task = queue.take();
// 再比较一下看看当前这个任务时间到了没?
long curTime = System.currentTimeMillis();
if (curTime < task.getTime()) {
// 时间没到, 把任务再塞回到队列中.
queue.put(task);
// 指定一个等待时间
synchronized (locker) {
locker.wait(task.getTime() - curTime);
}
} else {
// 时间到了, 执行这个任务
task.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
public class Demo24 {
public static void main(String[] args) {
MyTimer myTimer = new MyTimer();
myTimer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("hello timer!");
}
}, 3000);
System.out.println("main");
}
}
线程池
进程,比较重.频繁创建销毁,开销大
解决方案:进程池 or线程.
线程,虽然比进程轻了,但是如果创建销毁的频率进一步增加,仍然会发现开销还是有的~~解决方案:线程池or协程
java.util.concurrent…
Java中很多和多线程相关的组件都在这个concurrent包里
又叫做JUC
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo25 {
public static void main(String[] args) {
// 创建一个固定线程数目的线程池. 参数指定了线程个数
ExecutorService pool = Executors.newFixedThreadPool(10);
// 创建一个自动扩容的线程池. 会根据任务量来自动进行扩容
// Executors.newCachedThreadPool();
// 创建一个只有一个线程的线程池.
// Executors.newSingleThreadExecutor();
// 创建一个带有定时器功能的线程池. 类似于 Timer
// Executors.newScheduledThreadPool();
for (int i = 0; i < 100; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello threadpool");
}
});
}
}
}
标椎库中的线程池叫做 ThreadPoolExecutor
看最全的一个构造方法:
int corePoolSize:核心线程数
int maximumPoolSize:最大线程数
long keepAliveTime:允许非核心线程空闲时的保留时间
TimeUnit unit:时间单位
BlockingQueue workQueue:任务队列.线程池会提供一个submit方法让程序猿把任务注册到线程池中.加到这个任务队列中
ThreadFactory threadFactory:线程工厂.线程是怎么创建出来的
RejectedExecutionHandler handler:拒绝策略 ,当任务队列满了,怎么做?
1.直接忽略最新的任务2.阻塞等待
3.直接丢弃最老的任务
有一个程序,这个程序要并发的/多线程的来完成一些任务~~,如果使用线程池的话,这里的线程数设为多少合适??
正确做法:要通过性能测试的方式,找到合适的值
标准库中还提供了一个简化版本的线程池Executors
本质是针对ThreadPoolExecutor进行了封装,提供了一些默认参数
仿照这个提供一个线程池
class MyThreadPool {
// 1. 描述一个任务. 直接使用 Runnable, 不需要额外创建类了.
// 2. 使用一个数据结构来组织若干个任务.
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
// 3. 描述一个线程, 工作线程的功能就是从任务队列中取任务并执行.
static class Worker extends Thread {
// 当前线程池中有若干个 Worker 线程~~ 这些 线程内部 都持有了上述的任务队列.
private BlockingQueue<Runnable> queue = null;
public Worker(BlockingQueue<Runnable> queue) {
this.queue = queue;
}
@Override
public void run() {
// 就需要能够拿到上面的队列!!
while (true) {
try {
// 循环的去获取任务队列中的任务.
// 这里如果队列为空, 就直接阻塞. 如果队列非空, 就获取到里面的内容~~
Runnable runnable = queue.take();
// 获取到之后, 就执行任务.
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 4. 创建一个数据结构来组织若干个线程.
private List<Thread> workers = new ArrayList<>();
public MyThreadPool(int n) {
// 在构造方法中, 创建出若干个线程, 放到上述的数组中.
for (int i = 0; i < n; i++) {
Worker worker = new Worker(queue);
worker.start();
workers.add(worker);
}
}
// 5. 创建一个方法, 能够允许程序猿来放任务到线程池中.
public void submit(Runnable runnable) {
try {
queue.put(runnable);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Demo26 {
public static void main(String[] args) {
MyThreadPool pool = new MyThreadPool(10);
for (int i = 0; i < 100; i++) {
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello threadpool");
}
});
}
}
}