单例模式是一种确保某个类在程序中只有一个实例,并提供全局访问点的设计模式。以下是几种常见的单例模式实现方式及其线程安全保证方法:
饿汉式单例在类加载时就创建好实例对象,因此在程序调用时直接返回该单例对象即可。由于类加载的过程是线程安全的,所以饿汉式单例不存在线程安全问题。
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
懒汉式单例在第一次被调用时才创建对象,但简单的懒汉式实现存在线程安全问题。可以通过在getInstance()
方法上添加synchronized
关键字来保证线程安全。
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
双重检查锁定是一种优化后的懒汉式实现,通过两次if
判断和synchronized
块来保证线程安全,同时避免了synchronized
方法的性能问题。
public class DCLSingleton {
private volatile static DCLSingleton instance;
private DCLSingleton() {}
public static DCLSingleton getInstance() {
if (instance == null) {
synchronized (DCLSingleton.class) {
if (instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
}
静态内部类单例利用了JVM的类加载机制,只有在第一次调用getInstance()
方法时才会加载内部类并创建单例实例,因此是线程安全的。
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;
}
使用synchronized
关键字:通过同步整个方法或代码块来保证线程安全,但会降低性能。
双重检查锁定(DCL):通过两次if
判断和synchronized
块来保证线程安全,同时避免了性能问题。
利用JVM的类加载机制:静态内部类和枚举利用了JVM的类加载机制来保证线程安全,无需显式使用锁。
volatile
关键字:在DCL中,volatile
保证了线程之间的可见性,防止指令重排序带来的问题。
策略模式是一种行为型设计模式,它允许你定义一系列算法,把它们封装起来,并使它们可以互相替换。策略模式让你能够间接地选择算法,而无需修改使用该算法的代码。
策略模式的核心思想是将算法或行为抽取出来,封装在独立的类中,这些类被称为策略类。然后,通过一个上下文类来使用这些策略类,从而实现算法或行为的动态切换。
策略模式适用于以下场景:
以下是一个简单的策略模式示例,展示了如何实现不同的支付方式:
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略类:信用卡支付
public class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String name;
public CreditCardPayment(String cardNumber, String name) {
this.cardNumber = cardNumber;
this.name = name;
}
@Override
public void pay(double amount) {
System.out.println(amount + " paid with credit card.");
}
}
// 具体策略类:支付宝支付
public class AlipayPayment implements PaymentStrategy {
private String email;
public AlipayPayment(String email) {
this.email = email;
}
@Override
public void pay(double amount) {
System.out.println(amount + " paid with Alipay.");
}
}
// 上下文类
public class PaymentContext {
private PaymentStrategy paymentStrategy;
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void pay(double amount) {
paymentStrategy.pay(amount);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
PaymentContext context = new PaymentContext(new CreditCardPayment("1234567890", "John Doe"));
context.pay(100);
context.setPaymentStrategy(new AlipayPayment("[email protected]"));
context.pay(200);
}
}
在这个示例中,PaymentStrategy
是策略接口,CreditCardPayment
和 AlipayPayment
是具体策略类,PaymentContext
是上下文类。客户端代码可以通过设置不同的支付策略来动态地切换支付方式。
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法模式使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。
模板方法模式的核心思想是将不变的行为封装在超类中,而将可变的行为抽象成抽象方法或钩子方法,让子类去实现这些方法。这样,不同的子类可以以不同的方式实现这些可变步骤,而算法的整体结构和流程由超类控制。
模板方法模式适用于以下场景:
以下是一个简单的模板方法模式示例,展示了如何制作饮品的过程:
// 抽象类
public abstract class Beverage {
// 模板方法,定义了算法的骨架
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 基本操作
private void boilWater() {
System.out.println("Boiling water");
}
private void pourInCup() {
System.out.println("Pouring into cup");
}
// 抽象方法,由子类实现
protected abstract void brew();
protected abstract void addCondiments();
}
// 具体子类:咖啡
public class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("Dripping Coffee through filter");
}
@Override
protected void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
}
// 具体子类:茶
public class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("Steeping the tea");
}
@Override
protected void addCondiments() {
System.out.println("Adding Lemon");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Beverage coffee = new Coffee();
coffee.prepareRecipe();
System.out.println();
Beverage tea = new Tea();
tea.prepareRecipe();
}
}
在这个示例中,Beverage
是抽象类,定义了模板方法 prepareRecipe()
和一些基本操作。Coffee
和 Tea
是具体子类,实现了抽象方法 brew()
和 addCondiments()
。客户端代码通过创建不同的子类实例来执行不同的饮品制作过程。