单例模式
单例模式:程序中一个类只有一个实例对象
懒汉模式(类在加载的时候就已经被创建)
java
public class SingletonHungry {
// private保证这个类不会被外面修改
//static静态代码表示这个类全局唯一
private static SingletonHungry singletonHungry = new SingletonHungry();
//构造方法私有化,防止其他程序创建当前类的实例
private SingletonHungry() {}
//获取实例
private static SingletonHungry getInstance() {
return singletonHungry;
}
}
饿汉模式(使用的时候再被创建)
java
public class SingletonLazy {
private static volatile SingletonLazy singletonLazy = null;
private SingletonLazy() {
}
public static SingletonLazy getInstance() {
//第一次判断是否需要加锁,加锁是一个很耗资源的事情
if(singletonLazy == null) {
//加锁防止多个线程都在创建前判断为空,而导致都去创建
synchronized (SingletonLazy.class) {
//判断是否为空
if(singletonLazy == null) {
singletonLazy = new SingletonLazy();
}
}
}
return singletonLazy;
}
}
这种双重检查的操作叫做DCL
只要是多线程环境中修改了共享变量,就要给共享变量加volatile,通过synchronized原子性本身已经保证了内存可见性
这里类加volatile主要是考虑到指令重排序的问题
创建对象的过程可分为:
1.在内存中申请一片空间
2.初始化对象的属性
3.把对象在内存中的首地址赋给对象的引用
由于1执行之后就可以执行3,所以指令重排序可能是:1 3 2,但此时类没有初始化,就可能出现一些问题
阻塞队列
阻塞队列是一种特殊的队列,也遵循先进先出的原则。
阻塞队列也是一种线程安全的数据结构。并且:
当队列满的时候,继续入队就会阻塞,直到有其他线程从队列中取走元素,有空位再入队。
当队列空的时候,继续出队列也会阻塞,直到有其他线程往队列中插入元素,有元素再出队。
应用场景
消息队列
作用:
1.解耦:高内聚,低耦合
2.削峰填谷
3.异步操作
1.JDK提供的阻塞队列

java
public class Demo_01 {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> q = new ArrayBlockingQueue<>(3);
q.put(1);
System.out.println("添加了1");
q.put(2);
System.out.println("添加了2");
q.put(3);
System.out.println("添加了3");
q.put(4);
System.out.println("添加了4");
}
}

添加三个元素之后进行阻塞
java
public class Demo_01 {
public static void main(String[] args) throws InterruptedException {
BlockingQueue<Integer> q = new ArrayBlockingQueue<>(3);
q.put(1);
System.out.println("添加了1");
q.put(2);
System.out.println("添加了2");
q.put(3);
System.out.println("添加了3");
System.out.println(q.take());
System.out.println(q.take());
System.out.println(q.take());
System.out.println(q.take());
}
}

出队三个元素之后也进入了阻塞


2.自己实现阻塞队列
java
public class MyBlockingQueue {
// 定义一个数组来存放数据,具体的容量由构造方法中的参数决定
private Integer[] elementData;
// 定义头尾下标
private volatile int head = 0;
private volatile int tail = 0;
// 定义数组中元素的个数
private volatile int size = 0;
public MyBlockingQueue(int capacity) {
if(capacity <= 0) {
throw new IllegalArgumentException("参数不合法");
}
elementData = new Integer[capacity];
}
public synchronized void put(Integer x) {
//判断是否有位置插入,必须用while防止假唤醒
while (size >= elementData.length) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
elementData[head++] = x;
head = head % elementData.length;
size++;
this.notifyAll();
}
public synchronized Integer take() {
//判断是否有元素可以取
while (size == 0) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Integer ans = elementData[tail++];
tail = tail % elementData.length;
size--;
this.notifyAll();
return ans;
}
}
测试:
java
public class Demo_02 {
public static void main(String[] args) {
MyBlockingQueue myBlockingQueue = new MyBlockingQueue(3);
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
myBlockingQueue.put(i);
System.out.println("添加了元素: " + i);
}
});
Thread t2 = new Thread(() -> {
while (true) {
System.out.println("取出: " + myBlockingQueue.take());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t1.start();
t2.start();
}
}
