设计模式
2024年3月30日大约 3 分钟
单例模式
懒汉式
在首次被调用时才创建实例。
synchronized 关键字在争用激烈的场景下,内置锁会升级为重量级锁,开销大、性能差,所以不推荐高并发线程使用这种方式的单例模式。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}饿汉式
在类加载时就创建实例。
饿汉单例模式的优点是足够简单、安全。缺点是单例在类加载时实例直接初始化了,很多时候,类加载时并不需要进行单例初始化。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}双重检查锁
在多线程环境下使用懒加载,并且保证线程安全。
实际上,单例模式的加锁操作只有单例在第一次创建时才需要,在创建时保证只有一个线程能获取锁即可,之后的单例获取操作都没必要再加锁。
public class Singleton {
// volatile 防止指令重排导致高并发下第10行代码出错
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
// 第一次判断null可能多个线程都能通过,通过加锁操作,保证只有一个线程能创建。
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}静态内部类
利用类加载机制保证线程安全,且在使用时才加载内部类。
双重检查锁比较复杂,写法烦琐;静态内部类实现懒汉式单例模式也能保证线程安全,并且易于理解,推荐使用此种方式。
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}枚举
利用枚举的特性保证线程安全且实现简洁。
public enum Singleton {
INSTANCE;
// 可以添加其他方法或属性
}生产者-消费者模式
生产者线程(若干个)向数据缓冲区(DataBuffer)加入数据,消费者线程(若干个)从数据缓冲区消耗数据,需保证公用数据线程安全问题。生产者-消费者”模式是一个经典的多线程设计模式。
class Producer implements Runnable {
private final BlockingQueue<Integer> queue;
Producer(BlockingQueue<Integer> q) {
queue = q;
}
public void run() {
try {
for (int i = 0; i < 10; i++) {
queue.put(produce());
System.out.println("Produced: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
private int produce() {
return (int) (Math.random() * 100);
}
}
class Consumer implements Runnable {
private final BlockingQueue<Integer> queue;
Consumer(BlockingQueue<Integer> q) {
queue = q;
}
public void run() {
try {
while (true) {
consume(queue.take());
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
private void consume(Integer x) {
System.out.println("Consumed: " + x);
}
}
public class ProducerConsumerExample {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
Thread producerThread = new Thread(producer);
Thread consumerThread = new Thread(consumer);
producerThread.start();
consumerThread.start();
}
}模板模式
准备一个抽象类,将部分逻辑实现后,再声明一些抽象方法迫使子类实现剩余逻辑,不同的子类可实现不同逻辑。
模板模式的关键在于:父类提供框架性的公共逻辑,子类提供个性化的定制逻辑。
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
TemplateDame action = new ActionA(); // 子类A
action.tempMethod(); // 执行基类的模板方法
}
static abstract class TemplateDame {
// 模板方法,逻辑骨架
public void tempMethod()
{
System.out.println("模板方法的算法骨架被执行");
beforeAction(); // 执行前的公共操作
action(); // 调用钩子方法
afterAction(); // 执行后的公共操作
}
// 执行前 - 注意是protected修饰,此方法为父类逻辑的部分实现,不能被子类重写。
protected void beforeAction()
{
System.out.println("准备执行钩子方法");
}
// 钩子方法:这里定义为一个抽象方法
public abstract void action();
protected void afterAction()
{
System.out.println("钩子方法执行完成");
}
}
//子类A:提供了钩子方法实现,不同子类可自定义不同钩子逻辑。
static class ActionA extends TemplateDame
{
@Override
public void action()
{
System.out.println("钩子方法的实现 test.ActionA.action() 被执行");
}
}
}
