2_单例模式
2020-12-23 本文已影响0人
真是个点子王
- 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式;
- 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代码模式;
- 行为型模式:模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式
单例模式
- 单例模式就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得对象实例的方法。
-
Java写法分类
- 饿汉式(静态常量)
- 饿汉式(静态代码块)
- 懒汉式(线程不安全)
- 懒汉式(线程安全)
- Double Check
- 静态内部类
- 枚举
一、饿汉式(静态常量)
- 步骤如下:
- 1、构造器私有化;
- 2、类的内部创建对象;
- 3、向外暴露一个静态的方法;
- 4、代码实现
public class SingletonTest01 {
public static void main(String[] args) {
PersonManager manager = PersonManager.getInstance();
PersonManager manager1 = PersonManager.getInstance();
System.out.println(manager == manager1);
System.out.println(manager.hashCode());
System.out.println(manager1.hashCode());
}
}
class PersonManager{
// 2. 创建静态成员变量
private static final PersonManager INSTANCE = new PersonManager();
// 1. 将构造器私有化
private PersonManager(){
}
// 3.提供一个静态方法,返回实例对象
public static PersonManager getInstance() {
return INSTANCE;
}
}
优缺点:
- 1、优点:写法简单,就是在类加载的时候就完成实例化。避免了线程同步问题;
- 2、缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终未使用过这个实例,则会造成内存的浪费。
- 关于类加载的机制,这一块还没有学习。需要留个坑,以及为何会存在线程同步问题,也不能够理解。
二、饿汉式(静态代码块)
- 这种方式原理和方式一中相同,只不过是将静态变量的初始化操作放在了静态代码块中。
public class SingletonTest02 {
public static void main(String[] args) {
PersonManager02 manager = PersonManager02.getInstance();
PersonManager02 manager1 = PersonManager02.getInstance();
System.out.println(manager == manager1);
System.out.println(manager.hashCode());
System.out.println(manager1.hashCode());
}
}
class PersonManager02{
private static final PersonManager02 INSTANCE;
static {
INSTANCE = new PersonManager02();
}
private PersonManager02(){
}
public static PersonManager02 getInstance(){
return INSTANCE;
}
三、懒汉式(线程不安全)
- 在真正需要使用到类的对象的时候才去创建它。
public class Singleton03 {
public static void main(String[] args) {
PersonManager03 manager = PersonManager03.getInstance();
PersonManager03 manager1 = PersonManager03.getInstance();
System.out.println(manager == manager1);
System.out.println(manager.hashCode());
System.out.println(manager1.hashCode());
}
}
class PersonManager03{
private static PersonManager03 instance;
private PersonManager03(){
}
public static PersonManager03 getInstance(){
if(instance == null){
instance = new PersonManager03();
}
return instance;
}
}
- 可以起到懒加载的效果,但是只能在单线程下使用;
- 如果在多线程下,一个程序如果进入了
if(instance == null)
语句块,但是在还没有创建对象时,另外一个线程也进入了该块,会产生线程安全问题。
四、懒汉式(线程安全)
- 在
getInstance()
方法加上synchronized
可以解决线程安全问题
public class Singleton04 {
public static void main(String[] args) {
PersonManager04 manager = PersonManager04.getInstance();
PersonManager04 manager1 = PersonManager04.getInstance();
System.out.println(manager == manager1);
System.out.println(manager.hashCode());
System.out.println(manager1.hashCode());
}
}
class PersonManager04{
private static PersonManager04 instance;
private PersonManager04(){
}
public static synchronized PersonManager04 getInstance(){
if(instance == null){
instance = new PersonManager04();
}
return instance;
}
}
- 虽然解决了线程安全问题,但是效率太低。例如,后续操作可能只是单独的想获得该类的实例对象,但是每一次都需要进入到同步代码块中,太低效。
五、Double Check
- 这里
volatile
关键字的作用是为了避免在双重检测时指令重排而导致的安全问题。 - 关于具体的解释,可以参考这个博主的文章,感谢博主。
- https://www.cnblogs.com/xz816111/p/8470048.html
public class Singleton05 {
public static void main(String[] args) {
PersonManager05 manager = PersonManager05.getInstance();
PersonManager05 manager1 = PersonManager05.getInstance();
System.out.println(manager == manager1);
System.out.println(manager.hashCode());
System.out.println(manager1.hashCode());
}
}
class PersonManager05{
private static volatile PersonManager05 instance;
private PersonManager05(){
}
public static PersonManager05 getInstance(){
if(instance == null){
synchronized (PersonManager05.class){
if(instance == null) {
instance = new PersonManager05();
}
}
}
return instance;
}
}
六、静态内部类
- 静态内部类在其所属的类加载时, 内部类本身不发生加载;
- 当真正用到它时,才会加载(实现了延迟加载);
- 在类加载时初始化,线程安全。
- 步骤:
public class SingletonTest06 {
public static void main(String[] args) {
PersonManager05 manager = PersonManager05.getInstance();
PersonManager05 manager1 = PersonManager05.getInstance();
System.out.println(manager == manager1);
System.out.println(manager.hashCode());
System.out.println(manager1.hashCode());
}
}
class PersonManager06 {
// 1、私有化构造器
private PersonManager06(){
}
// 2、写一个静态内部类,该类中有一个静态属性Person
private static class PersonInstance{
private static final PersonManager06 INSTANCE = new PersonManager06();
}
// 3、提供一个静态的公有方法,直接返回Person.INSTANCE
public static PersonManager06 getInstance(){
return PersonInstance.INSTANCE;
}
}
七、枚举
public class SingletonTest07 {
public static void main(String[] args) {
PersonManager07 manager = PersonManager07.INSTANCE;
PersonManager07 manager1 = PersonManager07.INSTANCE;
System.out.println(manager == manager1);
System.out.println(manager.hashCode());
System.out.println(manager1.hashCode());
manager.sayOK();
}
}
enum PersonManager07{
INSTANCE;
public void sayOK(){
System.out.println("ok");
}
}