单例模式(Singleton Pattern)
单例模式定义:Ensure a class has only one instance,and provide a global point of access to it.(确保某一个类只有一个实例,自行实例化并提供一个全局访问点)
以下实现方式在多线程环境下都是没有问题的
实现一(对getInstance()方法进行同步,影响性能):
public class Singleton { private static Singleton instance = null; private Singleton(){} public synchronized static Singleton getInstance(){ if(null == instance){ instance = new Singleton(); } return instance; } }
public class Singleton { private static Singleton instance = null; private Singleton(){} public static Singleton getInstance(){ synchronized(Singleton.class){ if(null == instance){ instance = new Singleton(); } return instance; } } }
实现二(推荐方式):
instance可以是final的,也可以不是,我个人认为没什么影响
public class Singleton { private static Singleton instance = new Singleton(); //private final static Singleton instance = new Singleton();也是可以的 private Singleton(){} public static Singleton getInstance(){ return instance; } }
虚拟机将自动进行同步,详见:http://blog.csdn.net/a19881029/article/details/17068191
实现三:
过一段时间回来看这种实现方式,简直蠢透了,给自己提个醒,留在这里不删了,这种实现方式的问题如下:
1,instance参数既然使用了static修饰符,为什么还要使用volatile修饰符?
2,在同步方法getInstance的方法体内再次同步还有什么意义?
将方法本身的同步去掉,保留方法体内的同步可能是有意义的(减少同步范围),但是完全不能确定instance == null这步判断是否会产生原子性问题
虚拟机规范没有明确规定引用类型(reference,指向一个对象)占用32位还是占用64位(跟虚拟机具体实现有关),如果占用32位,则不会有原子性问题,如果占用64位,虚拟机需要分2次分别获取2个Slot内保存的值以得到一个完整的引用类型,此时将产生原子性问题(参考long和double)
public class Singleton { private static volatile Singleton instance; private Singleton(){ System.out.println(Math.random()); } public synchronized static Singleton getInstance(){ if(null == instance){ synchronized (Singleton.class) { instance = new Singleton(); } } return instance; } }
具体思想就是同步块内代码量越少,代码处理的速度越快,同步对性能的影响越小
jdk1.4及以下版本volatile变量的实现会导致该实现出现bug
单例模式也可以生成多个实例:
package com.test; import java.util.Random; import java.util.Vector; public class Connection { private static int max_num = 10; private static int num_count = 0; private static Vector<Connection> connPool = new Vector<Connection>(); static{ for( ; num_count < max_num ; num_count++){ Connection conn = new Connection(); System.out.println(num_count+":"+conn.hashCode()); connPool.add(conn); } } private Connection(){} public static Connection getConn() throws Exception{ Random random = new Random(); int num = random.nextInt(max_num); Connection conn = connPool.get(num); System.out.println(conn.hashCode()); return conn; } public static void main(String[] args) throws Exception{ for(int i = 0 ; i<5 ; i++){ Connection.getConn(); } } }
0:3526198 1:7699183 2:14285251 3:10267414 4:27553328 5:4072869 6:1671711 7:11394033 8:4384790 9:9634993 10267414 1671711 1671711 4072869 4384790