Java设计模式单例模式

来源:互联网 发布:网络推广软文范文 编辑:程序博客网 时间:2024/06/06 09:46

设计模式来源于生活,是生活的升华。

什么是单例模式

一种常见的设计模式,主要的写法:懒汉式,饿汉式、注册登记式。单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
懒汉式:看上去比较懒,不到火烧眉毛的时候,不着急实例化,需要用的时候才实例化。
饿汉式:不管用不用,都先实例化。
注册登记式:有一个容器装着所有实例,在实例产生前先检查一下容器看有没有,如果有就直接取出来,如果没有就先new一个放进去,然后留给后面用,如:Spring IOC容器。

哪里用到单例模式?

Spring中用的最多,在spring context,Factory中都有体现,bean默认是单例,配置文件是单例(多例了不知道以谁为准)。全局性的东西要用单例。如:Tomcat中的servletContext、application。

java加载的一些规则

1.从上往下加载
2.先静态后动态(静态块和static关键字修饰在实例化以前分配内存空间)
3.先属性后方法,成员变量不能定义在方法中,只能定义在class下。

七种创建方式

懒汉式

类在实例化前先声明静态属性singlenton,然后就可以共享这个实例了,构造方法的私有化使得类不能new出来,因此提供静态的获取实例方法。

package com.test;public class Singlenton1 {    //1.将构造方法私有化    private Singlenton1(){      }    //2.声明静态变量保存单例的引用    private static Singlenton1 singlenton=null;    //3.提供静态方法来获取单例的引用,这时遇到多个线程同时抢占cpu资源,该方法就会被new两次,两次的值不一样    public static Singlenton1 getSinglenton(){        if(singlenton==null){            singlenton=new Singlenton1();        }        return singlenton;    }}

懒汉式单例保证线程安全,加同步锁。

package com.test;public class Singlenton1 {    private Singlenton1(){      }    private static Singlenton1 singlenton=null;    //提供静态方法来获取单例的引用,为保证多线程环境下正确访问,给该方法加同步锁synchronized,保证了方法不能调用两次,但是new可以两次。    public static synchronized Singlenton1 getSinglenton(){        if(singlenton==null){            singlenton=new Singlenton1();        }        return singlenton;    }}

懒汉式双重锁检查

package com.test;public class Singlenton1 {    private Singlenton1(){      }    private static Singlenton1 singlenton=null;    //提供静态方法来获取单例的引用,为保证多线程环境下的另一种实现方式,双重锁检查    public static  Singlenton1 getSinglenton(){        if(singlenton==null){            synchronized (Singlenton1.class) {                if(singlenton==null)                    singlenton=new Singlenton1();            }           }        return singlenton;    }}

饿汉式

不会出现线程安全的问题,不管有多个线程,在加载之前已经完成了初始化,但是当这个实例一直没有被使用时,空间就会被浪费。

package com.test;public class Singlenton2 {    private Singlenton2(){      }    //声明静态变量,在类实例化之前就初始化变量,将对象引用保存    private static Singlenton2 singlenton=new Singlenton2();    //提供静态方法来获取实例    public static  Singlenton2 getSinglenton(){            return singlenton;    }}

懒汉式

最牛逼的方法,没有一个字母是多余的,也没有一个关键字是多余的。
内部类的初始化,需要依赖主类,给内部类加static关键字,即当我们JVM加载主类时内部类也被加载进来,但是还没实例化,需要等主类先实例化后内部类才开始实例化

package com.test;public class Singleton {    //构造方法私有化    private Singleton(){}    private static class InnerClass{        //final为了防止内部将这个属性值覆盖掉        private static final Singleton INSTANCE=new Singleton();    }    //加final是为了防止子类重写父类方法    public static final Singleton getImstance(){        return InnerClass.INSTANCE;    }}

枚举式不常用

package com.test;public enum Singleton3 {    INSTANCE;    public void getInstance(){      }}

注册登记式
spring最顶层容器Map,每个class对应一个id(唯一),容器启动后每个class实例化放在map中,根据查,若为null新建,有的话直接拿来用。

package com.test;import java.util.HashMap;import java.util.Map;public class Singleton4 {    //类似Spring里面的方法,将类名注册,下次从里面直接获取。    private static Map<String, Singleton4> map=new HashMap<String, Singleton4>();    static{        Singleton4 single=new Singleton4();        map.put(single.getClass().getName(), single);    }    //保护的默认构造    protected Singleton4(){}    //静态工厂方法,返回此类的唯一实例    public static Singleton4 getInstance(String name){        if(name==null){            name=Singleton4.class.getName();        }        if(map.get(name)==null){            try {                map.put(name, (Singleton4) Class.forName(name).newInstance());            } catch (InstantiationException e) {                e.printStackTrace();            } catch (IllegalAccessException e) {                e.printStackTrace();            } catch (ClassNotFoundException e) {                e.printStackTrace();            }        }        return map.get(name);    }}

线程并发访问单例

访问最牛逼的方式创建的

package com.test;import java.util.concurrent.CountDownLatch;public class Test {    public static void main(String[] args) {        //启动多个线程同时去抢cpu        int count=100;        //发令枪:多个线程同时发生。        CountDownLatch latch=new CountDownLatch(count);        for (int i = 0; i < count; i++) {            new Thread(){                public void run(){                    Singleton.getImstance();                    System.out.println(System.currentTimeMillis()+""+Singleton.getImstance());                }            }.start();            latch.countDown();        }        try {            latch.await();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

运行结果,从图中可以看出在并发的情况下也是同一个实例化。

这里写图片描述

原创粉丝点击