目录
单例模式
单例设计模式:确保一个类只有一个实例,且单例实例应该为static静态变量,保证全局唯一
单例模式实现方式:
饿汉模式<代码>
class Pattern {
private static Pattern instance = new Pattern();
private Pattern() {
// 设置为私有,目的是外部不能初始化
}
public static Pattern getInstance() {
return instance;
}
}
public class SinglePatternOne {
public static void main(String[] args) {
Pattern instance1 = Pattern.getInstance();
Pattern instance2 = Pattern.getInstance();
System.out.println(instance2 == instance1);
}
}
懒汉模式<代码>
class LazyPattern {
private volatile static LazyPattern instance;
private static Object locker = new Object();
private LazyPattern() {
// 设置为私有,目的是外部不能初始化
}
public static LazyPattern getInstance() {
if(instance == null) { // 只有第一次调用这个方法才加锁,之后调用就不用再进行加锁
synchronized (locker) { // 达到原子性效果
if(instance == null) {
instance = new LazyPattern();
/**
* new操作的指令
* 1:内存分配
* 2:初始化零值
* 3:执行构造函数
* 正常顺序:1-》2-》3
* 但是编译器优化机制,会导致指令重排序,编程 1-》3-》2
* 加上volatile关键字,解决编译器优化问题(内存可见性、指令重排序)
*/
}
}
}
return instance;
}
}
public class SinglePatternTwo {
public static void main(String[] args) {
LazyPattern instance1 = LazyPattern.getInstance();
LazyPattern instance2 = LazyPattern.getInstance();
System.out.println(instance1 == instance2);
}
}
阻塞队列
阻塞队列概念
阻塞队列:是线程安全的队列,是多线程编程中生产者-消费者模型的核心组件。支持队列空时阻塞获取操作,队列满时阻塞插入操作
阻塞队列解决的问题
阻塞队列:协调多个线程之间的工作,主要目的是减少锁竞争(锁竞争:多个线程竞争同一个锁。就是在线程1获取到locker还未释放,线程2就去获取locker,线程2就会阻塞)
阻塞队列工作原理
put(element)方法:插入元素,具有阻塞功能,队列满时进行阻塞
take()方法:移除并返回头部元素,具有阻塞功能,队列空时进行阻塞
阻塞队列中,只有这两个方法具有阻塞功能
阻塞队列的优/缺点
优点
减少资源竞争,提高效率
模块之间能更好的“解耦合”
可以做到削峰填谷(如果资源不够用,服务器就挂了)
缺点
系统结构复杂,维护高
引入队列层数太多,就会增加网络开销
模拟实现阻塞队列<代码>
class Queue {
private int[] queue = null;
private int head;
private int tail;
private int size;
private Object locker = new Object();
public Queue(int capacity) {
this.queue = new int[capacity];
}
public void put(int element) throws InterruptedException {
synchronized (locker) {
while (size >= queue.length) {
locker.wait(); // 队列满时,进行阻塞等待
}
queue[tail] = element;
tail++;
if(tail >= queue.length) {
tail = 0;
}
size++;
locker.notify();
}
}
public int take() throws InterruptedException {
synchronized (locker) {
while (size < queue.length) {
locker.wait(); // 队列为空时,进行阻塞
}
int result = head;
head++;
if(head >= queue.length) {
head = 0;
}
size--;
locker.notify();
return result;
}
}
}
public class MyBlockingQueue {
public static void main(String[] args) {
Queue queue = new Queue(10);
Thread thread1 = new Thread(() -> {
int i = 0;
while (i != 400) {
try {
queue.put(i);
System.out.println("存入队列:" + i);
i++;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(i == 20) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
Thread thread2 = new Thread(() -> {
int result = 0;
while (true) {
try {
result = queue.take();
System.out.println(result);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(result == 40) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
thread1.start();
thread2.start();
}
}
线程池
线程池概念
线程池:是一种管理和复用线程的机制,通过预先创建一组线程并统一管理任务执行
线程池解决的问题
- 避免频繁创建/销毁线程。降低资源消耗
- 任务到达时,直接使用空闲线程,无需等待线程创建。提高响应速度
- 防止无限制创建线程导致系统崩溃。管控并发数量
- 支持任务排队、拒绝策略、监控功能等。统一任务管理
线程池参数
1:corePoolSize 核心线程数目
2:maximumPoolSize 最大线程数目(最大线程数=核心线程数+临时线程数)
3:keepAliveTime 临时线程在终止前等待新任务的最长时间
4:unit 是keepAliveTime的时间单位(时、分、秒、毫秒)
5:workQueue 任务队列,队列仅保存由execute方法提交的可运行任务
6:threadFactory 线程工厂,执行器创建新线程时使用的工厂
7:handler 拒绝策略,达到线程边界或队列容量时使用拒绝策略
四种拒绝策略
- AbortPolicy 中止策略,总是抛出RejectedExecutionException异常
- CallerRunsPolicy 提交任务的线程自己执行任务
- DiscardOldestPolicy 丢弃队列中最老的一个任务,然后重新尝试提交当前任务
- DiscardPolicy 丢弃队列中最新的一个任务,不抛异常不通知
线程池工作流程
模拟实现线程池<代码>
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
class MyThreadPool {
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
// 安全的阻塞队列,用于存放任务
public void myThreadPool(int threads) {
for (int i = 0; i < threads; i++) { // 创建线程,用于取任务,并执行任务
Thread thread = new Thread(() -> {
try {
Runnable task = queue.take(); // 取任务
task.run(); // 执行任务
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
thread.start();
}
}
public void submit(Runnable task) throws InterruptedException {
queue.put(task); // 上传任务
}
}
public class MyFixedThreadPool {
// 只有核心线程数
public static void main(String[] args) throws InterruptedException {
MyThreadPool threadPool = new MyThreadPool();
threadPool.myThreadPool(10);
// threadPool.submit(new Runnable() { // 这样只提交了一个任务
// @Override
// public void run() {
// for (int i = 0; i < 20; i++) {
// System.out.println("任务:" + i);
// }
// }
// });
for (int i = 0; i < 30; i++) { // 这样就是多线程抢占式执行
int id = i;
threadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("任务:" + id);
}
});
}
}
}
定时器
定时器:用于在指定时间或周期性地执行任务的工具。能够同时管理多个任务,有一定数据结构来组织这些任务。广泛用于任务调度、超时控制等
模拟实现定时器<代码>
注意:
两个线程操作一个队列,可能引发线程安全问题,所以需要加锁(synchronied)
当队列为空时,线程应该阻塞等待;当任务还没到执行时间时,线程也要阻塞等待
class TimerTask implements Comparable<TimerTask> {
private Runnable task;
private long time; // 任务执行时间
public TimerTask(Runnable task, long delay) {
this.task = task;
this.time = System.currentTimeMillis() + delay;
}
public Runnable getTask() {
return task;
}
public long getTime() {
return time;
}
// 因为要将类放到优先级队列当中,所以需要给类指定比较规则(1:实现Comparable接口 / 2:自己写一个类,实现Comparator)
@Override
public int compareTo(TimerTask o) {
return (int)(this.time-o.time);
}
}
class MyTimer {
private PriorityQueue<TimerTask> queue = new PriorityQueue<>(); // 优先级队列,用于存放任务
private Object locker = new Object();
/**
* submit(xx)方法存放任务 和 此处取任务,执行任务,删除任务 -》是两个线程同时修改一个队列
* 两个线程同时修改一个队列,可能会引发线程安全问题-》所以需要加锁(synchronied)
*/
public MyTimer() { // 创建线程,取出任务,执行任务(到时间执行),删除任务
Thread thread = new Thread(() -> {
while (true) {
synchronized (locker) {
if (queue.isEmpty()) {
try {
locker.wait(); // 当队列为空时,就进行阻塞等待。队列中有任务时,就执行下面操作
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
TimerTask timerTask = queue.peek(); // 取出队首任务
long curTime = System.currentTimeMillis();
if (curTime < timerTask.getTime()) {
try {
locker.wait(timerTask.getTime() - curTime);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
timerTask.getTask().run(); // 执行任务(到时间执行任务)
queue.poll(); // 删除队首任务
}
}
}
});
thread.start();
}
public void submit(Runnable task, long delay) {
synchronized (locker) {
queue.offer(new TimerTask(task, delay)); // 任务存入队列
locker.notify();
}
}
}
public class Timer {
public static void main(String[] args) {
MyTimer myTimer = new MyTimer();
myTimer.submit(new Runnable() {
@Override
public void run() {
System.out.println("4s后执行");
}
}, 4000);
myTimer.submit(new Runnable() {
@Override
public void run() {
System.out.println("5s后执行");
}
}, 5000);
myTimer.submit(new Runnable() {
@Override
public void run() {
System.out.println("2s后执行");
}
}, 2000);
System.out.println("启动程序");
}
}