java程序性能优化之设计优化---单例pk
对于单例,很多人就要问了。为什么要使用单例,单例意义何在?
单例的产生是由于类的频繁使用,每次生成对象都要new,使用完值后GC要释放对象。这样一来系统性能降低,GC承受着巨大的压力。为了能够提升系统性能或其他,以及减轻GC压力。我们引进了单例模式。
首先我们来看三个经典的单例模式
import java.util.Map; import java.util.HashMap; class Single1 { static Single1 single = null; private Single1() { } public synchronized static Single1 getInstance() { if(single==null) { single= new Single1(); } return single; } } /** *单例模式类 *@author qxh *@version 1.0 2015/6/13 */ class Single2{ private static final Single2 instance;//静态变量存放对象的引用 /** *私有的构造方法 * */ private Single2() { } /** *静态初始化块进行初始化 * */ static { instance=new Single2(); } /** *获取单例对象的方法 *@param 无 *@return 存放该对象地址的引用 */ public static Single2 getInstance() { return instance; } } class Single3 { static Map<String,Single3> single_map= new HashMap<String,Single3>(); private Single3() { } static { Single3 single = new Single3(); single_map.put(single.getClass().getName(),single); } public static Single3 getInstance(String name) { if(name==null) { name = Single3.class.getName(); } if(single_map.get(name)==null) { try{ single_map.put(name,(Single3)Class.forName(name).newInstance()); }catch(Exception e) { } } return single_map.get(name); } } class TestThread extends Thread { public void run() { long begin=System.currentTimeMillis(); for(int i=1;i<100000;i++) //Single1.getInstance();//耗时about46 //Single2.getInstance();//耗时0 Single3.getInstance(null);//耗时0 System.out.println("spend: " +(System.currentTimeMillis()-begin)); } } public class Single { public static void main(String[] args) { TestThread t1 = new TestThread(); TestThread t2 = new TestThread(); TestThread t3 = new TestThread(); TestThread t4 = new TestThread(); TestThread t5 = new TestThread(); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
我们先来看下第二种一开始就用初始化块进行单例初始化,这样虽然可以避免多线程下造成的数据混乱但是没有做到延迟加载,可能会使程序初始化较慢,第一种方式为了用了延迟加载,加了锁,虽然做到同步和延迟加载,但为了延迟加载,而牺牲系统系能未免不妥。第三种登记注册式单例,由于使用单例类名作为key而map集合又不可重复再加上构造方法私有,由公共方法同过类名得到的实例有且只有一个。这种方式和第二种一样,做到了同步,却没有做到延迟加载。为此我们的程序还需进一步改进。
public class Single{ private Single() { } private static class SingleHolder{ private static final Single single = new Single(); } public static Single getInstance() { return SingleHolder.single; } }
这种单例使用内部类来维护单例模式,当加载Single类时内部类并不会被加载,从而保证单例类不会被初始化,做到了延迟加载。又由于单例类实例的获得实在内部类加载完(类创建是原子性的非并发)之后才返回的,也就是说第一次初始化调用getInstance()就对单例类对象进行了初始化(类似第一)第二种,所以说对多线程友好。即做到了延迟加载又做到多线程友好。系统初始化和系统性能都能得到提升。