这一节,我们主要来探讨一些多线程相关的设计模式。
单例模式单例模式,顾名思义,是能够保证某个类在程序中只能创建一个实例的设计模式。
其对象的实例化被限制了,只能创建一个,多了的创建不了。
在java中,通过
- 使用静态成员表示实例(唯一性)
- 让构造方法私有的方法(堵住了new创建实例的扣子)
来实现。
单例模式有饿汉模式和懒汉模式两种。
饿汉模式:程序启动,立刻创建实例
class Singleton{
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
private Singleton(){}
}
懒汉模式
懒汉模式:程序启动,不立刻创建实例;类加载的同时,创建实例
class SingletonLazy{
private static SingletonLazy instance = null;
public static SingletonLazy getInstance(){
if(instance == null){
instance = new SingletonLazy();//写
}
return instance;
}
private SingletonLazy(){}
}
- 对于饿汉模式,由于只涉及到多线程读,所以它的线程是安全的
- 对于懒汉模式,创建实例的时候涉及多线程读写,所以线程是不安全的,后面的线程安全
class SingletonLazy{
volatile private static SingletonLazy instance = null;
public static SingletonLazy getInstance(){
if(instance == null){
synchronized (SingletonLazy.class){
if(instance == null){
instance = new SingletonLazy();
}
}
}
return instance;
}
private SingletonLazy(){}
}
if(instance == null){instance = new SingletonLazy();}这步操作在多线程下,可能会出现多个线程进入if判断,从而创建多个实例。这时候,我们需要用synchronized来限制线程的进入。
另外,由于只是在创建实例的时候可能会出现线程不安全的情况,而synchronized的开销非常大,后期我们要尽可能的避免synchronized,故而在代码块的外面增加一个if(instance == null)的判断,来减小synchronized的开销。
生产者消费者模式生产者消费者模式的优点:
- 可以做到更好的“解耦合”
- 能够做到“削峰填谷”,提高整个系统的抗风险能力
public class Demo19 {
public static void main(String[] args) {
BlockingQueue queue = new LinkedBlockingQueue<>();
Thread customer = new Thread(() -> {
while(true){
try {
int elem = queue.take();
System.out.println("消费了:"+elem);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
customer.start();
Thread producer = new Thread(() -> {
int elem = 0;
while(true){
System.out.println("生产了:"+elem);
try {
queue.put(elem);
elem++;
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producer.start();
}
}
上述代码使用了一个阻塞队列,这是java自带的,下面我们将模拟实现一下阻塞队列
阻塞队列class MyBlockingQueue{
private int[] arr = new int[1000];
private int head = 0;
private int tail = 0;
private int size = 0;
public void put(int val) throws InterruptedException {
synchronized (this){
while(size == arr.length){//此处需要while进行再次判断
this.wait();
}
arr[head] = val;
tail++;
if(tail == arr.length){
tail = 0;
}
size++;
this.notify();
}
}
public Integer take() throws InterruptedException {
synchronized (this){
while(size == 0){
this.wait();
}
int ret = arr[head];
head++;
if(head == arr.length){
head = 0;
}
size--;
this.notify();
return ret;
}
}
}



