简述
设计模式类型有3种(创建型,结构型,行为型)
以下逐一列出创建型类型的设计模式:
1单例,2原型,3工厂,4抽象工厂,5构建者(创建者)模式。
一、单例模式
单例模式就是在一个jvm中只能创建一个对象;分饿汉式单例模式和懒汉式单例模式。
- 饿汉式是加载类的时候就创建该对象。
- 懒汉式为用的时候才创建该对象。
适用场景
spring中bean的创建默认单例模式
应用服务器有很多系统参数在服务运行期间不会改变的,可用单例创建。
饿汉式demo
- 饿汉式单例模式,类加载的时候就实例化对象,线程安全。
- 简单实用,推荐
- 个人认为 不算严重的一个缺点,不管用到与否,类装载时就完成实例化
/**饿汉式 线程安全,加载类时就创建对象*/
public class Mgr01 {
private static final Mgr01 INSTANCE=new Mgr01();//2 私有静态化常量来创建对象
private Mgr01(){};//1私有化构造方法
public static Mgr01 getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
Mgr01 m1=Mgr01.getInstance();
Mgr01 m2=Mgr01.getInstance();
System.out.println(m1==m2);
}
}
懒汉式demo
demo1 方法,效率低下,不推荐
- 解决按需初始化,线程安全
- 特点:在方法上加同步代码块,效率低
public class Mgr04 {
private static Mgr04 INSTANCE;
private Mgr04(){
}
public static synchronized Mgr04 getInstance(){ //synchronized 锁定当前对象,加了static 锁定的是class对象
if(INSTANCE==null){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE=new Mgr04();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i=0;i<100;i++){
new Thread(()-> System.out.println(getInstance().hashCode())).start();
}
}
}
以下为3种较好的懒汉式单例实现demo,用到时才实例化
2 双重检查,即在同步块前后分别加实例判空逻辑
- spring容器中注册bean的获取,就是采用双重检查懒加载的单例模式;
- 传统懒汉式单例中,被认为是最好的懒汉式单例**<后面还有两个不错的单例>**
/**懒汉式
* 满足按需初始化,满足线程安全
* 较好1
* */
public class Mgr06 {
private static volatile Mgr06 INSTANCE;//JIT
private Mgr06(){}
public static Mgr06 getInstance(){
if(null==INSTANCE){
synchronized (Mgr06.class){
if(null==INSTANCE){//双重检查
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE=new Mgr06();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for(int i=1;i<100;i++){
new Thread(()-> System.out.println(getInstance().hashCode())).start();
}
}
}
3 运用虚拟机类加载知识,懒汉式:静态内部类方式
- 满足按需初始化,且线程安全
- jvm保证单例,加载外部类时不加载私有静态内部类,可以实现懒加载
public class Mgr07 {
private Mgr07(){}
private static class Mgr07Holder {
private static final Mgr07 INSTANCE=new Mgr07();
}
public static Mgr07 getInstance(){
return Mgr07Holder.INSTANCE;
}
public static void main(String[] args) {
new Thread(()-> System.out.println(getInstance().hashCode())).start();
}
}
4 解决线程同步,且能防止反序列化(因为枚举类没有构造方法)
- 源自effective java 是java原作者写的一本书
- 最优单例,可防止反序列化,线程安全
- 饿汉式单例
public enum Mgr08 {
INSTANCE;
public static void main(String[] args) {
for (int i=1;i<100;i++){
new Thread(()-> System.out.println(Mgr08.INSTANCE.hashCode())).start();
}
}
}