论坛首页 Java企业应用论坛

关于JAVA单例模式

浏览 52244 次
精华帖 (1) :: 良好帖 (2) :: 新手帖 (7) :: 隐藏帖 (12)
作者 正文
   发表时间:2012-03-15  
lunadancer 写道
Fkron 写道
今天和一人讨论以下这几形式的单例,看这样写是否正确??
public class Singleton
{
    private static Singleton st;
    
    public static Singleton getInstance()
    {
        if (null == st)
        {
            return new Singleton();
        }
        return st;
    }
}



他说这样写不对。。晕了。。


可能他是这个意思, 你每次都new一个新的对象那还叫单例么?
public class Singleton
{
    private static Singleton st;
    
    public static Singleton getInstance()
    {
        synchronize(Singleton.class){
            if (null == st)
            {
                st = new Singleton();
            }
        }
        return st;
    }
}



哈哈,楼上正解。开始我也以为说的是线程问题。
0 请登录后投票
   发表时间:2012-03-15  
837062099 写道
coollzh 写道
考虑lazy load的话,可以用double check技术。

不过double check有时候也不是100%线程安全的


多线程情况下,直接在方法上加synchronized同步,但是不够效率,事实上,只需要同步一次就可以了。
double check + volatile就100%安全了,取消编译器优化。
public class Singleton {
	
	private static volatile Singleton st;

       private Singleton (){}

	public static Singleton getInstance() {
		if (null == st) {
			synchronized (Singleton.class) {
				if (st == null) {
					st = new Singleton();
					return st;
				}
			}
		}
		return st;
	}
}

这个算是终极解决办法了。不过在分步式的环境下,要注意使用单例,因为单例,只是在一个JVM上的单例,多个JVM上的对象并不一样。
0 请登录后投票
   发表时间:2012-03-15  
//懒汉模式 
public class Singleton {
	private static Singleton st;
	private Singleton(){
	}
	public static Singleton getInstance() {
		if (null == st) {
			//处理多线程的问题,如果第一次访问枷锁 之后不在枷锁
			synchronized (Singleton.class){
				st = new Singleton();
			}
		}
		return st;
	}
}

//饿汉模式 
 class Singleton1 {
	private static Singleton1 st = new Singleton1();
	private Singleton1(){
	}
	public static Singleton1 getInstance() {
		return st;
	}
}

  

 

0 请登录后投票
   发表时间:2012-03-15  
错了,楼主的确错了。。。大意了
0 请登录后投票
   发表时间:2012-03-15  
http://xupo.iteye.com/blog/463426看看这个吧
0 请登录后投票
   发表时间:2012-03-15   最后修改:2012-03-15
/**
 * @author lee
 * @date Mar 5, 201210:09:12 AM
 * @version V1.0
 * @todo 单例模式属于对象创建型模式,其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点
 */
public class Singleton {
	private static Singleton instance;
	private static Singleton instance1=new Singleton();
	private static Singleton instance2;
	private static Singleton instance3;
	private volatile static Singleton instance4;
	//私有构造方法,避免外部创建实例
	private Singleton(){
	}
	//懒汉式单例>当需要的时候,并且发现没有实例的时候,才去初始化.
	public static Singleton getInstance(){
		if(instance==null){
			threadSleep();
			instance=new Singleton();
		}
		return instance;
	}
	//饿汉式单例>管你需要不需要,反正我是饿了,类加载的时候就已经初始化,没有起到延迟加载的效果
	public static Singleton getInstance1(){
		return instance1;
	}
	//对懒汉式进行同步,牺牲了性能,同步的原则应该是尽量对代码块同步,不要对整个方法同步
	public static synchronized Singleton getInstance2(){
		if(instance2==null){
			threadSleep();
			instance2=new Singleton();
		}
		return instance2;
	}
	//双重检查加锁DCL(double checking lock),只在第一次调用getInstance()时才要同步,提高性能
	public static Singleton getInstance3(){
		if(instance3==null){
			threadSleep();
			synchronized (Singleton.class) {
				if(instance3==null){
					instance3=new Singleton();
				}
			}
		}
		return instance3;
	}
	
	public static Singleton getInstance4(){
		if(instance4==null){
			threadSleep();
			synchronized (Singleton.class) {
				if(instance4==null){
					instance4=new Singleton();
				}
			}
		}
		return instance4;
	}
	//让当前线程休眠1秒,模拟多个线程同时访问instance==null之后的临界情况
	public static void threadSleep(){
		try {
			System.out.println("当前线程休眠1秒!");
			Thread.currentThread().sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

上面几种是常见的单例写法,下面分别弄几个线程测试一下,
public class ThreadTest extends Thread {
	
	@Override
	public void run() {
		Singleton s=Singleton.getInstance();
		System.out.println(s.toString());
		
		/*Singleton s1=Singleton.getInstance1();
		System.out.println(s1.toString());*/
		
		/*Singleton s2=Singleton.getInstance2();
		System.out.println(s2.toString());*/
		
		/*Singleton s3=Singleton.getInstance3();
		System.out.println(s3.toString());*/
	}
	public static void main(String[] args) {	
		for(int i=0;i<3;i++){
			ThreadTest test=new ThreadTest();
			test.start();
		}		
	}
}


把RUN方法里的注释,去掉,一次执行一个方法,发现除了第一个在多线程环境下不能实现真正的单例,其他的方法好像都是可以的。。。
网上有说DCL方法在JAVA中也不能实现真正的单例,不过,这测试结果好像也是可以的,还有那个volatile 关键字也不知道是弄啥的?
  • 大小: 22.9 KB
0 请登录后投票
   发表时间:2012-03-15  
单例是相对的。并不能做到完全正确的单例,用户可以通过系列化再反系列化的方式得到多份示例。
0 请登录后投票
   发表时间:2012-03-15   最后修改:2012-03-15
mfkvfn 写道
单例是相对的。并不能做到完全正确的单例,用户可以通过系列化再反系列化的方式得到多份示例。

只要没有implements Serializable就无法序列化的

即使实现这个接口了,在类里加入readResolve方法返回this即可保证反序列化不会得到多个实例
0 请登录后投票
   发表时间:2012-03-15   最后修改:2012-03-15
致命伤是没有赋值给st,其次没有私有构造,另外最好加上锁。
0 请登录后投票
   发表时间:2012-03-15  
当然不正确
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics