单例模式(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
浙公网安备 33010602011771号