java单例

xjpshh 2010-02-12 10:18:54
public final class EagerSingleton
{
private static EagerSingleton singObj = new EagerSingleton();

private EagerSingleton()
{
}

public static EagerSingleton getSingleInstance()
{
return singObj;
}
}
为什么说这个类是线程安全的呢?如果多线程访问那这个类只有一个实例怎么是线程安全的呢?
...全文
190 14 打赏 收藏 转发到动态 举报
写回复
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
awusoft 2010-02-23
  • 打赏
  • 举报
回复
引用 5 楼 gardner2010 的回复:
我们通常所说的,单例模式线程安全,是相对于单例模式线程不安全而言。一个线程不安全的例子如下:
Java codepublicfinalclass EagerSingleton
{privatestatic EagerSingleton singObj=null;private EagerSingleton()
{
}publicstatic EagerSingleton getSingleInstance()
{if (singObj==null) {
singObj=new EagerSingleton();
}return singObj;
}
}

getSingleInstance()方法线程不安全,多线程同时访问时,会产生多个实例,那样就不是单例模式了,因为不支持多线程访问,所以称之线程不安全。
而LZ所写的代码,多线程访问时,都是一个实例,不会产生多实例的情况,依然是单例模式。因为支持多线程访问,所以说线程安全,



呵呵,回答得太好了,终于知道了还会存在这样的问题.
ssss598026960 2010-02-23
  • 打赏
  • 举报
回复
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;
}
}
dinghun8leech 2010-02-12
  • 打赏
  • 举报
回复
上面有关我的回答我先道个歉,原来此贴讨论的问题点我没看清楚。
饿汉模式是在类加载时就实例化这唯一的对象,懒汉模式是在获取单例的方法中再行判断和实例化,因此前者就并发获取同一实例时是安全的,后者不安全。
我的理解是这个单例实例作为并发访问的资源是否安全的问题了,呵呵。
再次道歉。
dinghun8leech 2010-02-12
  • 打赏
  • 举报
回复
学习7楼这位兄弟,总算发现了,懒汉模式是在单例获取方法里进行判断和第一次建立对象,并发调用时有可能获得不同的对象。
xjpshh 2010-02-12
  • 打赏
  • 举报
回复
如果使用synchronized那不仅性能上不好,还可能出现死锁
xjpshh 2010-02-12
  • 打赏
  • 举报
回复
我简单的测试了一下,得到的hashcode都一样,不过比较迷惑的是如果我在这个类中添加一些变量和方法,多线程访问这个类中的变量或者方法,我觉得也也不能保证那这些变量和方法是线程安全的
soli11722984 2010-02-12
  • 打赏
  • 举报
回复
。。。。。。。。LS的,偶这里的机器就有重复了,而且你说“要想使上面的单件模式变成线程安全的,只要为getInstance加上synchronized关键字即可。”这不敢认同,因为你这样只是在返回单一个实例上是同步了,不过并不是代表获得了这个实例的类,再进行操作的时候是同步
chinaskyone 2010-02-12
  • 打赏
  • 举报
回复
这个主要是针对单例模式说的,单例有饿汉和懒汉模式,你的属于饿汉模式,并且是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关键字即可。
dinghun8leech 2010-02-12
  • 打赏
  • 举报
回复
引用 5 楼 gardner2010 的回复:
getSingleInstance()方法线程不安全,多线程同时访问时,会产生多个实例,那样就不是单例模式了,因为不支持多线程访问,所以称之线程不安全。
而LZ所写的代码,多线程访问时,都是一个实例,不会产生多实例的情况,依然是单例模式。因为支持多线程访问,所以说线程安全,

这也只能说所有线程获得的都是同一个实例而已呀。
小贝壳666 2010-02-12
  • 打赏
  • 举报
回复
我们通常所说的,单例模式线程安全,是相对于单例模式线程不安全而言。一个线程不安全的例子如下:
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所写的代码,多线程访问时,都是一个实例,不会产生多实例的情况,依然是单例模式。因为支持多线程访问,所以说线程安全,
dinghun8leech 2010-02-12
  • 打赏
  • 举报
回复
引用 1 楼 knightzhuwei 的回复:
线程之间没有共享变量当然是安全的

晕了。。。。。这个单例实例不就是共享的么?
bobo364 2010-02-12
  • 打赏
  • 举报
回复
类要成为线程安全的,首先必须在单线程环境中有正确的行为。如果一个类实现正确(这是说它符合规格说明的另一种方式),那么没有一种对这个类的对象的操作序列(读或者写公共字段以及调用公共方法)可以让对象处于无效状态,观察到对象处于无效状态、或者违反类的任何不可变量、前置条件或者后置条件的情况。

此外,一个类要成为线程安全的,在被多个线程访问时,不管运行时环境执行这些线程有什么样的时序安排或者交错,它必须仍然有如上所述的正确行为,并且在调用的代码中没有任何额外的同步。其效果就是,在所有线程看来,对于线程安全对象的操作是以固定的、全局一致的顺序发生的。

正确性与线程安全性之间的关系非常类似于在描述 ACID(原子性、一致性、独立性和持久性)事务时使用的一致性与独立性之间的关系:从特定线程的角度看,由不同线程所执行的对象操作是先后(虽然顺序不定)而不是并行执行的。

dinghun8leech 2010-02-12
  • 打赏
  • 举报
回复
哪里线程安全了?所以地方调用getSingleInstance()得到的都是同一个对象,并发操作会出问题的。
knightzhuwei 2010-02-12
  • 打赏
  • 举报
回复
线程之间没有共享变量当然是安全的

62,568

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告