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()就对单例类对象进行了初始化(类似第一)第二种,所以说对多线程友好。即做到了延迟加载又做到多线程友好。系统初始化和系统性能都能得到提升。  

  

posted @ 2015-08-16 16:07  kimoyoyo21  阅读(747)  评论(0编辑  收藏  举报