日期:2014-05-20  浏览次数:20861 次

单例模式中关于线程同步问题,先谢了
java ee中,有一dao调数据库,该dao实现单例模式,即有

public class PersonDAO{
  private static PersonDAO personDAO = new PersonDAO();
  private PersonDAO(){}
  public static PersonDAO getInstance(){
  return personDAO;
  }
}

这样可实现一个单例,但是有一个疑问:
1.当两个浏览器(也就是两个线程)同时调用PersonDAO时,这两个线程是不是同步的?
 (也就是说a线程获得personDAO对象时,b线程只能等待a线程调用结束?) 

2.别人说两个线程可以并发调用PersonDAO,我感觉很奇怪,personDAO是static的,也就是说在内存中只有一份,怎么可以同时被两个线程获取呢?

------解决方案--------------------
public class PersonDAO
的单例模式和并发没有任何关联!

单例模式,在jvm中只有一个对象!多个线程调用这个对象的方法,没有任何问题的,
不过非常重要的原则就是:不要再DAO中写成员变量,

public class PersonDAO
private String id;
private String name;
private String user;
上面的成员数据都存在一个对象中,会使数据大乱!

你的数据,VO(value object)都通过方法参数传递!
如:
public class PersonDAO
public void save(User user){代码}
public void update(User user){}
这样每个线程调用就不会有问题了!

这些概念也容易混淆,spring中的IoC的bean注入,都是单子模式,没有问题的!
------解决方案--------------------
引用楼主 walkiing 的帖子:
这样可实现一个单例,但是有一个疑问:
1.当两个浏览器(也就是两个线程)同时调用PersonDAO时,这两个线程是不是同步的?
(也就是说a线程获得personDAO对象时,b线程只能等待a线程调用结束?)

2.别人说两个线程可以并发调用PersonDAO,我感觉很奇怪,personDAO是static的,也就是说在内存中只有一份,怎么可以同时被两个线程获取呢?

------解决方案--------------------
同一个对象怎么不能被多个线程调用呢,没有问题的,只是不是同步的,也就是说你的这个对象不是线程安全的,方法可以被多个线程同时使用,这也就是1楼兄弟所说的你要是在该对象里有成员变量,那这些值就得不到保证了,因为你是单例,通过具体的方法参数来用本地变量就OK了
------解决方案--------------------
一个对象(数据)被多个线程访问,有两种方式:
1.非写操作, 即各个线程只是读其中的数据,这时不需要同步,因为线程之间读到的数据是相互之间没有影响的,这时减弱为互斥(即一个时间内只能有一个线程对其进行读)
2.写操作 这涉及到数据的统一性,因此也要互斥,但是如果a线程的处理结果要为b线程所用,那么加强为a,b线程同步

------解决方案--------------------
探讨
Landor2004 说得有点意思了
其实我就是想知道 既然是同一个对象(static的嘛),怎么能同时(也就是并发)被两个线程调用呢? 我觉得是不是分身术.. :)

------解决方案--------------------
探讨
这个是叫什么饿汉式单例,不需要线程同步
另外一种懒汉式的,就是调用方法时才生成对象这种才需要同步

------解决方案--------------------
探讨
引用:
public class PersonDAO
的单例模式和并发没有任何关联!

单例模式,在jvm中只有一个对象!多个线程调用这个对象的方法,没有任何问题的,
不过非常重要的原则就是:不要再DAO中写成员变量,

public class PersonDAO
private String id;
private String name;
private String user;
上面的成员数据都存在一个对象中,会使数据大乱!

你的数据,VO(value object)都通过方法参数传递! …

------解决方案--------------------
首先,建议楼主先抛开高层的概念,了解一下最基本的东西。
类是什么?类就是一堆抽象的代码,我们人类的概念,计算机不管;
对象是什么?对象就是一块内存,计算机仅仅认为它是一块内存;
单例是什么?单例就是仅仅有一块这样的内存,别的地方没有同样的;
线程是什么?线程就是一个过程,拥有一个跑起来的环境(堆栈....);
并发是什么?并发就是多个过程(线程)进展的逻辑时间没有关系(姑且先不管与并行的区别);
同步是什么?同步就是多个过程进展的逻辑时间的严格顺序性。
明白了以上的概念以后,我们来看看你的问题:
1.两个线程是否同步呢?实际上两个线程在没有显式同步的情况下就是不同步的,那么是否会引起并发问题呢?答案是如果你的单例里面没有成员变量就不会有问题,因为那个单例没有成员变量就剩下了一堆方法,而方法是在代码段里面的,进一步,线程拥有自己的堆栈,所有方法调用都在自己堆栈上进行,数据都是自己通过参数提供的,肯定在自己的存储空间(局部变量在堆栈,全局变量共享,靠线程安全解决),操作自己的堆栈别人管的着吗?但是,如果你的单例有成员变量,那么,操作成员变量就不是在自己的堆栈了,而是在单例的存储区,因此会有多个线程同时操作,从而引起问题。
2.为何两个线程都可以得到单例的对象呢?实际上,看了上面的分析以后,单例只不过是一块内存而已,底层的操作全是指针操作(java里没指针,但jvm还是c实现的,根本操作还是指针),不同的线程获得同一个指针难道有何问题吗?

希望对lz有帮助