单例模式
- 饿汉式(静态常量);
- 饿汉式(静态代码块);
- 懒汉式(线程不安全);
- 懒汉式(线程安全,同步方法);
- 懒汉式(线程安全,同步代码块);
- 双重检查;
- 静态内部类;
- 枚举
推荐使用:枚举、静态内部类、双重检查、饿汉式(可能造成浪费)
饿汉式
静态常量
//饿汉式(静态常量)
class Singleton {
//1、构造器私有化,外部不能new
private Singleton() {
}
//2、本类内部创建对象实例
private final static Singleton instance = new Singleton();
//3、提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
设计了一个私有静态的final对象,对外开放一个接口返回这个对象
静态代码块
class Singleton {
//1、构造器私有化,外部不能new
private Singleton() {
}
//2、静态代码块
private static Singleton instance;
static {
instance = new Singleton();
}
//3、提供一个公有的静态方法,返回实例对象
public static Singleton getInstance() {
return instance;
}
}
把新建对象放在一个静态的代码块里
优点:简单,类加载就完成实例化,避免线程同步问题
缺点:类加载就完成实例化,回到是内存浪费
懒汉式
//懒汉式(线程不安全)
class Singleton {
private static Singleton instance;
private Singleton() {
}
//提供一个静态的公有方法,当使用到该方法时,才去创建instance
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优点:起到了懒加载的效果,但是只能在单线程下使用;
缺点:如果在多线程下,一个线程进入了if(singleton==null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。
//懒汉式(线程安全,同步方法)
class Singleton {
private static Singleton instance;
private Singleton() {
}
//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
synchronized
加在方法上
优点:加了synchronized
解决线程安全问题
缺点:效率低
//懒汉式(线程安全,同步代码块)
class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
与上面一种方法的区别是它把synchronized关键字放在了代码块
缺点:看似安全实则不安全:进入if
后可能有其他线程也进入if
双重检查(重点)
public class SingletonTest {
public static void main(String[] args) {
Singleton instance = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance == instance2);
}
}
//双重检查
class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
volatile
防止指令重排,方法上加synchronized
,执行两次if (instance == null)
,第二次之前先执行synchronized
。
静态内部类
//静态内部类
class Singleton {
private Singleton() {
}
//写一个静态内部类,该类中有一个静态属性Singleton
private static class singleInstance {
private static final Singleton INSTANCE = new Singleton();
}
//提供一个静态的公有方法,直接返回对象
public static synchronized Singleton getInstance() {
return singleInstance.INSTANCE;
}
}
- 静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,会装载SingletonInstance类,从而完成Singleton的实例化;
- 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的;
枚举
public class SingletonTest8 {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance == instance2);
instance.sayOK();
}
}
//使用枚举,可以实现单例
enum Singleton {
INSTANCE;//属性
public void sayOK() {
System.out.println("ok");
}
}
工厂模式
简单工厂模式
不需要自己new对象,使用factory创建
工厂方法模式
抽象工厂模式
适配器模式
假设存在三个对象:Computer(想上网,没有网口),Usb(网线接口转换为Usb),Online(网线)
类适配器
继承:Usb继承Online,Computer调用Usb
对象适配器
组合:Usb中创建Online对象,Computer调用Usb
代理模式
静态代理
定义接口
定义被代理对象实现接口
定义代理对象,代理对象中实现被代理对象
调用代理对象的方法调用被代理对象