单例模式-java实现

介绍

单例模式的意图:保证某个类在系统中有且仅有一个实例。

我们可以看到下面的类图:一般的单例的实现,是属性中保持着一个自己的私有静态实例引用,还有一个私有的构造方法,然后再开放一个静态的获取实例的方法给外界获取实例对象。

 

单例模式-java实现_第1张图片

 

代码实现

在java中有两种实现的方法

  • 饿汉式:在类加载的时候就创建好实例
  • 懒汉式:在请求实例时才创建实例

饿汉式

在类加载的时候就创建好实例

public class TestObj {
    private static TestObj testObj=new TestObj();
    //构造方法私有化
    private TestObj(){

    }
    //提供一个外界获取单实例的静态方法
    public static  TestObj getTestObj(){
        return testObj;
    }
}

懒汉式

由于java是多线程的,很有可能多个线程同时进入,导致创建多个实例,于是我们要使用锁机制来让线程之间互斥访问

public class TestObj2 {
    //初始,维护一个静态的空引用
    private static TestObj2 testObj2=null;
    //私有的构造方法
    private TestObj2(){

    }
    //提供给外界获取单实例的静态方法
    public static TestObj2 getTestObj2(){
        //在这里,由于java是多线程的,很有可能多个线程同时进入,导致创建多个实例,于是我们要使用锁机制来让线程之间互斥访问
        //多线程同时判断,如果不为null,直接返回
        if (testObj2!=null){
            return testObj2;
        }
        //使用同步代码块进行线程互斥访问
        synchronized (Object.class){
            //其他线程进入以后,如果已经创建好了对象,则直接返回
            if (testObj2!=null){
                return testObj2;
            }
            else {
                //初始化单实例
                testObj2=new TestObj2();
            }

        }
        return testObj2;

    }
}

我们这里测试一下:

创建三个线程同时去获取实例,看输出的地址是否一样

//创建一个runable接口
class DoTask implements Runnable{
    @Override
    public void run() {
        //获取实例对象并输出
        TestObj2 testObj2 = TestObj2.getTestObj2();
        System.out.println(testObj2);
    }
}

class Main{
    public static void main(String[] args) {
        Runnable runnable=new DoTask();
        //创建多个线程去获取实例
        Thread thread1=new Thread(runnable);
        Thread thread2=new Thread(runnable);
        Thread thread3=new Thread(runnable);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

运行结果:

可以看到输出的三个地址都是相同的,因此我们上面的懒汉式代码是完全可行的,这里仅仅讨论单服务器的情况,如果是分布式系统中的单实例,就要考虑使用分布式锁,或者redis,zookeeper等分布式协调工具去完成了

 

单例模式-java实现_第2张图片

你可能感兴趣的:(设计模式,笔记,JAVA,java,单例模式,开发语言)