单例模式之懒汉的并发问题,只需要添加一个 synchronized 就可以解决了
2017-02-26 12:26
344 查看
复现并发问题:
package review.bank;
/**
* Created by kodulf on 2017/2/26.
*/
public class SingleInstanceLazyMan {
private SingleInstanceLazyMan(){
}
static SingleInstanceLazyMan singleInstanceLazyMan ;
//synchronized 如果不添加,那么会出现三个进程一起调度的情况
public static SingleInstanceLazyMan getInstance(){
if(singleInstanceLazyMan==null){
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
singleInstanceLazyMan = new SingleInstanceLazyMan();
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
}
return singleInstanceLazyMan;
}
}
新建三个进程去调用这个单例的getInstance方法
public static void testSingleInstance(){
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
SingleInstanceLazyMan.getInstance();
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
SingleInstanceLazyMan.getInstance();
}
});
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
SingleInstanceLazyMan.getInstance();
}
});
thread1.start();
thread2.start();
thread3.start();
}
运行结果:会发现都调用了if == null的那个判断了,就是执行了里面的程序了
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-0
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
Process finished with exit code 0
要解决这个问题:
只需要添加一个单词,synchronized 就可以了
package review.bank;
/**
* Created by zhangyinshan on 2017/2/26.
*/
public class SingleInstanceLazyMan {
private SingleInstanceLazyMan(){
}
static SingleInstanceLazyMan singleInstanceLazyMan ;
//synchronized 如果不添加,那么会出现三个进程一起调度的情况
public static synchronized SingleInstanceLazyMan getInstance(){
if(singleInstanceLazyMan==null){
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
singleInstanceLazyMan = new SingleInstanceLazyMan();
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
}
return singleInstanceLazyMan;
}
}
运行结果:只调用了一次,这个就是我们想要的
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
Process finished with exit code 0
package review.bank;
/**
* Created by kodulf on 2017/2/26.
*/
public class SingleInstanceLazyMan {
private SingleInstanceLazyMan(){
}
static SingleInstanceLazyMan singleInstanceLazyMan ;
//synchronized 如果不添加,那么会出现三个进程一起调度的情况
public static SingleInstanceLazyMan getInstance(){
if(singleInstanceLazyMan==null){
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
singleInstanceLazyMan = new SingleInstanceLazyMan();
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
}
return singleInstanceLazyMan;
}
}
新建三个进程去调用这个单例的getInstance方法
public static void testSingleInstance(){
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
SingleInstanceLazyMan.getInstance();
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
SingleInstanceLazyMan.getInstance();
}
});
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
SingleInstanceLazyMan.getInstance();
}
});
thread1.start();
thread2.start();
thread3.start();
}
运行结果:会发现都调用了if == null的那个判断了,就是执行了里面的程序了
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-0
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-1
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
before new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-1
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
after new Thread-2
Process finished with exit code 0
要解决这个问题:
只需要添加一个单词,synchronized 就可以了
package review.bank;
/**
* Created by zhangyinshan on 2017/2/26.
*/
public class SingleInstanceLazyMan {
private SingleInstanceLazyMan(){
}
static SingleInstanceLazyMan singleInstanceLazyMan ;
//synchronized 如果不添加,那么会出现三个进程一起调度的情况
public static synchronized SingleInstanceLazyMan getInstance(){
if(singleInstanceLazyMan==null){
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
System.out.println("before new "+Thread.currentThread().getName());
singleInstanceLazyMan = new SingleInstanceLazyMan();
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
System.out.println("after new "+Thread.currentThread().getName());
}
return singleInstanceLazyMan;
}
}
运行结果:只调用了一次,这个就是我们想要的
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
before new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
after new Thread-0
Process finished with exit code 0
相关文章推荐
- 只有一个公网IP也可以使用LVS的DR模式!(外带php session粘滞问题解决)
- 只有一个公网IP也可以使用LVS的DR模式!(外带php session粘滞问题解决)
- 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为(转)
- 一个发邮件的类,带验证功能,可以发html内容,可以添加附件,并解决附件乱码问题。
- 基本上,把switch,用设计模式代替,肯定是bug和过度设计。想想,本来修改一个文件几行代码可以解决的问题,变成修改3-6个类才能实现一样的功能。不是傻是什么?
- 想做一个可以赚钱的网站需要解决哪些问题
- iOS 如何巧妙解决“一个任务需要等待另外一个任务完成后才可以执行”的问题
- 一个发邮件的类,带验证功能,可以发html内容,可以添加附件,并解决附件乱码问题。
- 【转】一个非常常见但容易被忽略的c++问题——用IPML模式可以解决
- 一个发邮件的类,带验证功能,可以发html内容,可以添加附件,并解决附件乱码问题。
- 关于报表中同一个数据源下添加多个数据集得问题解决
- 把同一个Resource添加到同一个Group中两个不同Application导致的问题及解决方法
- 通过一个小技巧可以让flash和iframe的在ie下遮挡问题解决
- 用Factory设计模式解决一个网友的问题
- 用NSIS安装日志install。log解决了一个安装出现隐蔽的问题、不用看代码,可以节省大把时间!开心!
- 组合设计模式,解决struts只能有一个资源文件的问题
- 约瑟夫环加强版用线段树解决m,,这类问题还可以拓展,只是一个思路,用线段树的思路要学习
- VS2008中解决方案只能添加一个项目的问题解决
- 管理是需要的。我是在99年接触csdn的。那时在csdn上看帖子,订程序员杂志,真是感觉获益非浅,由于工作的原因又一段时间没有上csdn。前几天和别的公司程序员聊天,我无意中说道,可以去csdn找找帮助呀,也许程序上的问题就解决了,他的回答让我吃了一惊,c
- 设计模式的实际应用――在C#中解决单客户端窗口数据并发问题