public final class EagerSingleton  
 {  
     private static EagerSingleton singObj = new EagerSingleton();  
  
    private EagerSingleton()  
    {  
    }  
   
     public static EagerSingleton getSingleInstance()  
     {  
         return singObj;  
     }  
 }  
为什么说这个类是线程安全的呢?如果多线程访问那这个类只有一个实例怎么是线程安全的呢?

解决方案 »

  1.   

    哪里线程安全了?所以地方调用getSingleInstance()得到的都是同一个对象,并发操作会出问题的。
      

  2.   

    类要成为线程安全的,首先必须在单线程环境中有正确的行为。如果一个类实现正确(这是说它符合规格说明的另一种方式),那么没有一种对这个类的对象的操作序列(读或者写公共字段以及调用公共方法)可以让对象处于无效状态,观察到对象处于无效状态、或者违反类的任何不可变量、前置条件或者后置条件的情况。此外,一个类要成为线程安全的,在被多个线程访问时,不管运行时环境执行这些线程有什么样的时序安排或者交错,它必须仍然有如上所述的正确行为,并且在调用的代码中没有任何额外的同步。其效果就是,在所有线程看来,对于线程安全对象的操作是以固定的、全局一致的顺序发生的。正确性与线程安全性之间的关系非常类似于在描述 ACID(原子性、一致性、独立性和持久性)事务时使用的一致性与独立性之间的关系:从特定线程的角度看,由不同线程所执行的对象操作是先后(虽然顺序不定)而不是并行执行的。
      

  3.   

    我们通常所说的,单例模式线程安全,是相对于单例模式线程不安全而言。一个线程不安全的例子如下:
    public final class EagerSingleton  
    {  
        private static EagerSingleton singObj = null; 
      
        private EagerSingleton()  
        {  
        }  
      
         public static EagerSingleton getSingleInstance()  
        {  
            if (singObj == null) {
                singObj = new EagerSingleton(); 
            }
            return singObj;  
        }  
    }  getSingleInstance()方法线程不安全,多线程同时访问时,会产生多个实例,那样就不是单例模式了,因为不支持多线程访问,所以称之线程不安全。
    而LZ所写的代码,多线程访问时,都是一个实例,不会产生多实例的情况,依然是单例模式。因为支持多线程访问,所以说线程安全,
      

  4.   

    这个主要是针对单例模式说的,单例有饿汉和懒汉模式,你的属于饿汉模式,并且是static的,所以,在取实例的时候就不会同时得到多个实例,不管多少个线程调用,都是同一个实例的引用被返回。
    如果是懒汉模式,构造子也没有同步,那多个线程调用的时候,就可能返回多个实例,也就失去了单例的意义。比如:package test;// 线程安全的Singleton模式
    class Singleton
    {
        private static Singleton sample;    private Singleton()
        {
        }
        public static Singleton getInstance()
        {
            if (sample == null)
            {
                Thread.yield(); // 为了放大Singleton模式的线程不安全性
                sample = new Singleton();
            }
            return sample;
        }
    }
    public class MyThread extends Thread
    {
        public void run()
        {
            Singleton singleton = Singleton.getInstance();
            System.out.println(singleton.hashCode());
        }
        public static void main(String[] args)
        {
            Thread threads[] = new Thread[5];
            for (int i = 0; i < threads.length; i++)
                threads[i] = new MyThread();
            for (int i = 0; i < threads.length; i++)
                threads[i].start();
        }
    } 在上面的代码调用yield方法是为了使单件模式的线程不安全性表现出来,如果将这行去掉,上面的实现仍然是线程不安全的,只是出现的可能性小得多。    程序的运行结果如下:
    25358555
    26399554
    7051261
    29855319
    5383406 
        上面的运行结果可能在不同的运行环境上有所有同,但一般这五行输出不会完全相同。从这个输出结果可以看出,通过getInstance方法得到的对象实例是五个,而不是我们期望的一个。这是因为当一个线程执行了Thread.yield()后,就将CPU资源交给了另外一个线程。由于在线程之间切换时并未执行到创建Singleton对象实例的语句,因此,这几个线程都通过了if判断,所以,就会产生了建立五个对象实例的情况(可能创建的是四个或三个对象实例,这取决于有多少个线程在创建Singleton对象之前通过了if判断,每次运行时可能结果会不一样)。    要想使上面的单件模式变成线程安全的,只要为getInstance加上synchronized关键字即可。
      

  5.   

    。。LS的,偶这里的机器就有重复了,而且你说“要想使上面的单件模式变成线程安全的,只要为getInstance加上synchronized关键字即可。”这不敢认同,因为你这样只是在返回单一个实例上是同步了,不过并不是代表获得了这个实例的类,再进行操作的时候是同步
      

  6.   

    我简单的测试了一下,得到的hashcode都一样,不过比较迷惑的是如果我在这个类中添加一些变量和方法,多线程访问这个类中的变量或者方法,我觉得也也不能保证那这些变量和方法是线程安全的
      

  7.   

    如果使用synchronized那不仅性能上不好,还可能出现死锁
      

  8.   

    public class Singleton { private static Singleton singleton=null;

    private Singleton(){

    }

    public static Singleton getInstance(){
    if(singleton==null){//防止第一次调用的时候有多个线程同时调用
    synchronized (Singleton.class){//如果为空,线程同步
    if(singleton==null){
    singleton=new Singleton();
    }
    }
    }
    return singleton;
    }
    }