java优化之 单例模式的优化

该分类下的文章均为笔者阅读《Java程序性能优化》(葛一鸣)一书之所理解。如有欠缺,还请大佬们指点。

单例模式

单例模式用来创建的对象可以确保系统中只产生一个示例。主要有以下两种好处:
1.对于频繁使用的对象可以省略创建对象所花费的时间
2.由于new操作的次数减少,对系统内存的使用频率也会降低。将减轻GC压力。缩短GC停顿时间。

创建单例模式

public class SingleClassDemo {

    //第一种方式 直接创建对象 需要时直接返回
    public static SingleClassDemo sSingleClassDemo = new SingleClassDemo();

    private SingleClassDemo() {
        System.out.println("创建单例对象");
    }


    public static SingleClassDemo getInstance() {
        return sSingleClassDemo;
    }


    // 该类中的其他静态方法
    //public static String otherMethod() {
    //    return "otherMethod otherMethod!";
    //}

}

/**
*	测试类
*/
public class TestSingleClassDemo {
    @Test
    public void testInstance() {

        SingleClassDemo instance = SingleClassDemo.getInstance();
        System.out.println(instance);
        //打印结果:创建单例对象  top.wintp.demo.SingleClassDemo@50486d1d
    }
}
 

如上述代码就是单例模式的一种简单的实现方式。试想我们这种实现方式会有什么问题呢?
当该类中存在其他的静态方法的时候,我们直接调用该类的其他静态方法,也会创建该类的对象,这是我们不想得到的结果

调用示例:

public class TestSingleClassDemo {
    @Test
    public void testInstance() {
        //当调用该类的其他方法的时候,会初始化该类该类的静态变量 创建对象
        String string = SingleClassDemo.otherMethod();
        System.out.println(string);
        //打印结果:创建单例对象        cotherMethod otherMethod!
    }
}

单例模式优化一(懒加载模式)

修改创建单例对象的时机,当有需要的时候再去创建对象。


public class LazSingleClassDemo {

    private static LazSingleClassDemo mLazSingleClassDemo = null;

    private LazSingleClassDemo() {
        System.out.println("创建懒加载模式的对象");
    }

    public static LazSingleClassDemo getmLazSingleClassDemo() {

        if (mLazSingleClassDemo == null) {
            mLazSingleClassDemo = new LazSingleClassDemo();
        }

        return mLazSingleClassDemo;
    }

    public static String otherMehod() {

        return "otherMehod otherMehod";
    }
}



public class TestSingleClassDemo {
    @Test
    public void testInstance() {

        //    懒加载模式
        //在懒加载模式中 调用该类的其他方法并不会创建该类的对象
        String string = LazSingleClassDemo.otherMehod();
        System.out.println(string);
        //打印结果:otherMehod otherMehod
    }
}

当多线程并发时,懒加载模式就可能会出现,当前线程检测为null,第二个线程检测为null,同时创建两个对象的情况。那就违背了单例的原则。

调用示例:


public class TestSingleClassDemo {
    @Test
    public void testInstance() {
        //    懒加载模式的线程并发问题
        new Thread("t1") {
            public void run() {
                LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(lazSingleClassDemo);
            }
        }.start();
        new Thread("t2") {
            public void run() {
                LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(lazSingleClassDemo);
            }
        }.start();
        new Thread("t3") {
            public void run() {
                LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(lazSingleClassDemo);
            }
        }.start();
        new Thread("t4") {
            public void run() {
                LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(lazSingleClassDemo);
            }
        }.start();

        new Thread("t5") {
            public void run() {
                LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(lazSingleClassDemo);
            }
        }.start();


        /*
		打印结果如下:
		
        创建懒加载模式的对象
        创建懒加载模式的对象
        t2
        top.wintp.demo.LazSingleClassDemo@475f260c
        t1
        top.wintp.demo.LazSingleClassDemo@55b9171e
        t3
        top.wintp.demo.LazSingleClassDemo@475f260c
        t4
        top.wintp.demo.LazSingleClassDemo@475f260c
        t5
        top.wintp.demo.LazSingleClassDemo@475f260c
         */
    }
}

单例模式优化二(懒加载模式线程并发问题)

使用同步方法避免多线程并发。


public class LazSingleSyncClassDemo {

    private static LazSingleSyncClassDemo mLazSingleClassDemo = null;

    private LazSingleSyncClassDemo() {
        System.out.println("创建懒加载模式同步方法的对象");
    }

	//使用synchronized 关键字
    public static synchronized LazSingleSyncClassDemo getmLazSingleClassDemo() {

        if (mLazSingleClassDemo == null) {
            mLazSingleClassDemo = new LazSingleSyncClassDemo();
        }

        return mLazSingleClassDemo;
    }

    public static String otherMethod() {

        return "otherMethod otherMethod";
    }
}

如上代码,再次进行多线程进行调用就不会出现创建多个对象的结果
线程安全避免不了的就是性能会降低。下面就是线程同步与线程不同的测试程序执行时长


public class TestSingleClassDemo {
    @Test
    public void testInstance() {
        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            LazSingleClassDemo lazSingleClassDemo = LazSingleClassDemo.getmLazSingleClassDemo();
        }
        long endTime = System.currentTimeMillis();

        System.out.println(endTime - beginTime);
        //懒加载模式 不同步方法 用时间:    2


        beginTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            LazSingleSyncClassDemo lazSingleClassDemo = LazSingleSyncClassDemo.getmLazSingleClassDemo();
        }
        endTime = System.currentTimeMillis();

        System.out.println(endTime - beginTime);
        //懒加载模式 同步方法 用时间:    5

    }
}


单例模式优化三(使用静态内部类进行优化)


public class EndSingleClassDemo {

    private static EndSingleClassDemo mLazSingleClassDemo = null;

    private EndSingleClassDemo() {
        System.out.println("创建懒加载模式的对象");
    }


    /**
     * 静态内部类
     */
    private static class EndSingleClassDemoHolder {
        private static EndSingleClassDemo mLazSingleClassDemo = new EndSingleClassDemo();
    }

    public static EndSingleClassDemo getmLazSingleClassDemo() {

        return EndSingleClassDemoHolder.mLazSingleClassDemo;
    }

    public static String otherMehod() {

        return "otherMehod otherMehod";
    }
}


public class TestSingleClassDemo {
    @Test
    public void testInstance() {
        new Thread("t1") {
            public void run() {
                EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(endSingleClassDemo);
            }
        }.start();
        new Thread("t2") {
            public void run() {
                EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(endSingleClassDemo);
            }
        }.start();
        new Thread("t3") {
            public void run() {
                EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(endSingleClassDemo);
            }
        }.start();
        new Thread("t4") {
            public void run() {
                EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(endSingleClassDemo);
            }
        }.start();
        new Thread("t5") {
            public void run() {
                EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
                System.out.println(this.getName());
                System.out.println(endSingleClassDemo);
            }
        }.start();


        long beginTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            EndSingleClassDemo endSingleClassDemo = EndSingleClassDemo.getmLazSingleClassDemo();
        }
        long endTime = System.currentTimeMillis();

        System.out.println("用时间:" + (endTime - beginTime));
       
        /*
        打印结果如下:
        
        创建懒加载模式的对象
        t1
        t2
        t3
        top.wintp.demo.EndSingleClassDemo@4dbb3e34
        top.wintp.demo.EndSingleClassDemo@4dbb3e34
        top.wintp.demo.EndSingleClassDemo@4dbb3e34
        t4
        top.wintp.demo.EndSingleClassDemo@4dbb3e34
        t5
        top.wintp.demo.EndSingleClassDemo@4dbb3e34
        用时间:1
         */

    }
}


一个优秀的程序员,不仅要会编写程序,更要学会编写高质量的程序。
事虽难,做则成;路虽远,行则至。

你可能感兴趣的:(java优化之 单例模式的优化)