关于单例模式和多线程之间无法实现的问题
2014-09-22 15:33
302 查看
单例模式:保证一个类仅有一个势力,并提供一个访问它的全局访问点,在编程实现的时候,我想让两个线程t1,、t2分别访问该实例,而且是互斥的访问,虽然Instance的互斥实现了,但是关于createSingletonInstance()的互斥访问却没有实现,请问这是问什么,希望各位大虾给予解答,thx。
首先是Singleton类:
/**
*Singleton.java
*/
package shejimoshi.singleton;
/**
* @author xuhongbin
* @data2014年9月21日上午10:37:55
*/
public class Singleton {
private static Singleton instance;
private Singleton(){//构造方法让其private, 这就毒死了外界利用new 创建此类实例的可能
}
public static synchronized Singleton GetInstance(){
if(instance == null){
instance = new Singleton();
System.out.println(Thread.currentThread().getName()+"创建了instance实例");
}
return instance;
}
}
其次是线程及主函数:
/**
*TestSingleton.java
*/
package shejimoshi.singleton;
/**
* @author xuhongbin
* @data2014年9月21日下午2:30:37
*/
public class TestSingleton implements Runnable{
public static int i;
Singleton s;
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
createSingletonInstance();
}
public synchronized void createSingletonInstance(){
s = Singleton.GetInstance();
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"线程调用了一个Singleton对象");
System.out.println("第"+i+"次调用Singleton对象。。。。。");
}
/**
* @param args
*/
public static void main(String[] args) {
Thread t1 = new Thread(new TestSingleton(), "ss1");
Thread t2 = new Thread(new TestSingleton(), "ss2");
t1.start();
t2.start();
}
}
一直出现这样的结果:
ss2创建了instance实例
ss2线程调用了一个Singleton对象
ss1线程调用了一个Singleton对象
第2次调用Singleton对象。。。。。
第2次调用Singleton对象。。。。。
而我想要线程互斥的访问,也就是后两句应该一个是“第1次调用......”, “第2次调用......”
希望尽快得到大家的解答,谢谢。。。
问题在这里http://bbs.csdn.net/topics/390890982?page=1#post-398229236
首先非常感谢:software_gemeng;javaliuliu;liudehuas5的解答
更改后代码如下:main函数做出了以下修改:
然后运行成功,
结果为:
ss1创建了instance实例
ss1线程调用了一个Singleton对象
第1次调用Singleton对象。。。。。
ss2线程调用了一个Singleton对象
第2次调用Singleton对象。。。。。
问题的本质在于对synchronized,线程理解的不到位。
createSingletonInstance方法前加synchronized关键字是加对象锁,对象锁是对特定实例加锁(同一TestSingleton对象),而非对TestSingleton类进行加锁。
在原始编码中,new了两个TestSingleton对象,他们是属于同一类的不同对象。所以即使有synchronized加锁,也不会有不同对象对i互斥访问。
而singleton的实例instance 为何可以实现互斥访问,原因是只有一个Singleton的实例instance,所以会互斥访问,那么接下来我们继续做实验:
将TestSingleton的i的static关键字去掉。
main函数中new出两个TestSingleton对象
(与原始代码相比只是将 TestSingleton中的static去掉,我想自己出现该错误的思维盲点就在这里,
Thread t1 = new Thread(new TestSingleton(), "s1");
Thread t2 = new Thread(new TestSingleton(), "s2");)
完全没有意识到是new出两个TestSingleton对象儿出现的问题)
那么更改后的代码为:
/**
*TestSingleton.java
*/
package shejimoshi.singleton;
/**
* @author xuhongbin
* @data2014年9月21日下午2:30:37
*/
public class TestSingleton implements Runnable{
public int i;
Singleton s;
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
createSingletonInstance();
}
public synchronized void createSingletonInstance(){
s = Singleton.GetInstance();
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"线程调用了一个Singleton对象");
System.out.println("第"+i+"次调用Singleton对象。。。。。");
}
/**
* @param args
*/
public static void main(String[] args) {
TestSingleton s1 = new TestSingleton();
TestSingleton s2 = new TestSingleton();
Thread t1 = new Thread(s1, "s1");
Thread t2 = new Thread(s2, "s2");
t1.start();
t2.start();
}
}
运行结果为:
s1创建了instance实例
s2线程调用了一个Singleton对象
s1线程调用了一个Singleton对象
第1次调用Singleton对象。。。。。
第1次调用Singleton对象。。。。。
这下对于概念的理解就更加明了,由于是不同的Singleton对象,所以即使在createSingletonInstance()前加synchronized,也只能保证 特定TestSingleton实例(new出的TestSingleton对象,如s1,或者是s2)之间对i访问的互斥,而无法保证对对不同TestSingleton对象(如s1和s2)对i的互斥访问。
主函数如下更改则脉络更加清晰:
结果为:
s20创建了instance实例
s20线程调用了一个Singleton对象
s10线程调用了一个Singleton对象
第1次调用Singleton对象。。。。。
第1次调用Singleton对象。。。。。
s11线程调用了一个Singleton对象
第2次调用Singleton对象。。。。。
s21线程调用了一个Singleton对象
第2次调用Singleton对象。。。。。
可以看出 对象s1与s2之间的变量i毫无关系,而线程对象t10和t11(或者是t20和t21)之间对i的访问是互斥的。而且由于Single的实例instance只有一个且对调用它的函数是互斥访问的,所以instance在全局是互斥的。
终于搞明白了。。。
首先是Singleton类:
/**
*Singleton.java
*/
package shejimoshi.singleton;
/**
* @author xuhongbin
* @data2014年9月21日上午10:37:55
*/
public class Singleton {
private static Singleton instance;
private Singleton(){//构造方法让其private, 这就毒死了外界利用new 创建此类实例的可能
}
public static synchronized Singleton GetInstance(){
if(instance == null){
instance = new Singleton();
System.out.println(Thread.currentThread().getName()+"创建了instance实例");
}
return instance;
}
}
其次是线程及主函数:
/**
*TestSingleton.java
*/
package shejimoshi.singleton;
/**
* @author xuhongbin
* @data2014年9月21日下午2:30:37
*/
public class TestSingleton implements Runnable{
public static int i;
Singleton s;
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
createSingletonInstance();
}
public synchronized void createSingletonInstance(){
s = Singleton.GetInstance();
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"线程调用了一个Singleton对象");
System.out.println("第"+i+"次调用Singleton对象。。。。。");
}
/**
* @param args
*/
public static void main(String[] args) {
Thread t1 = new Thread(new TestSingleton(), "ss1");
Thread t2 = new Thread(new TestSingleton(), "ss2");
t1.start();
t2.start();
}
}
一直出现这样的结果:
ss2创建了instance实例
ss2线程调用了一个Singleton对象
ss1线程调用了一个Singleton对象
第2次调用Singleton对象。。。。。
第2次调用Singleton对象。。。。。
而我想要线程互斥的访问,也就是后两句应该一个是“第1次调用......”, “第2次调用......”
希望尽快得到大家的解答,谢谢。。。
问题在这里http://bbs.csdn.net/topics/390890982?page=1#post-398229236
首先非常感谢:software_gemeng;javaliuliu;liudehuas5的解答
更改后代码如下:main函数做出了以下修改:
public static void main(String[] args) { TestSingleton s = new TestSingleton(); Thread t1 = new Thread(s, "ss1"); Thread t2 = new Thread(s, "ss2"); t1.start(); t2.start(); }
然后运行成功,
结果为:
ss1创建了instance实例
ss1线程调用了一个Singleton对象
第1次调用Singleton对象。。。。。
ss2线程调用了一个Singleton对象
第2次调用Singleton对象。。。。。
问题的本质在于对synchronized,线程理解的不到位。
createSingletonInstance方法前加synchronized关键字是加对象锁,对象锁是对特定实例加锁(同一TestSingleton对象),而非对TestSingleton类进行加锁。
在原始编码中,new了两个TestSingleton对象,他们是属于同一类的不同对象。所以即使有synchronized加锁,也不会有不同对象对i互斥访问。
而singleton的实例instance 为何可以实现互斥访问,原因是只有一个Singleton的实例instance,所以会互斥访问,那么接下来我们继续做实验:
将TestSingleton的i的static关键字去掉。
main函数中new出两个TestSingleton对象
(与原始代码相比只是将 TestSingleton中的static去掉,我想自己出现该错误的思维盲点就在这里,
Thread t1 = new Thread(new TestSingleton(), "s1");
Thread t2 = new Thread(new TestSingleton(), "s2");)
完全没有意识到是new出两个TestSingleton对象儿出现的问题)
那么更改后的代码为:
/**
*TestSingleton.java
*/
package shejimoshi.singleton;
/**
* @author xuhongbin
* @data2014年9月21日下午2:30:37
*/
public class TestSingleton implements Runnable{
public int i;
Singleton s;
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
createSingletonInstance();
}
public synchronized void createSingletonInstance(){
s = Singleton.GetInstance();
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"线程调用了一个Singleton对象");
System.out.println("第"+i+"次调用Singleton对象。。。。。");
}
/**
* @param args
*/
public static void main(String[] args) {
TestSingleton s1 = new TestSingleton();
TestSingleton s2 = new TestSingleton();
Thread t1 = new Thread(s1, "s1");
Thread t2 = new Thread(s2, "s2");
t1.start();
t2.start();
}
}
运行结果为:
s1创建了instance实例
s2线程调用了一个Singleton对象
s1线程调用了一个Singleton对象
第1次调用Singleton对象。。。。。
第1次调用Singleton对象。。。。。
这下对于概念的理解就更加明了,由于是不同的Singleton对象,所以即使在createSingletonInstance()前加synchronized,也只能保证 特定TestSingleton实例(new出的TestSingleton对象,如s1,或者是s2)之间对i访问的互斥,而无法保证对对不同TestSingleton对象(如s1和s2)对i的互斥访问。
主函数如下更改则脉络更加清晰:
public static void main(String[] args) { TestSingleton s1 = new TestSingleton(); TestSingleton s2 = new TestSingleton(); Thread t10 = new Thread(s1, "s10"); Thread t11 = new Thread(s1, "s11"); Thread t20 = new Thread(s2, "s20"); Thread t21 = new Thread(s2, "s21"); t10.start(); t11.start(); t20.start(); t21.start(); }
结果为:
s20创建了instance实例
s20线程调用了一个Singleton对象
s10线程调用了一个Singleton对象
第1次调用Singleton对象。。。。。
第1次调用Singleton对象。。。。。
s11线程调用了一个Singleton对象
第2次调用Singleton对象。。。。。
s21线程调用了一个Singleton对象
第2次调用Singleton对象。。。。。
可以看出 对象s1与s2之间的变量i毫无关系,而线程对象t10和t11(或者是t20和t21)之间对i的访问是互斥的。而且由于Single的实例instance只有一个且对调用它的函数是互斥访问的,所以instance在全局是互斥的。
终于搞明白了。。。
相关文章推荐
- 巧妙解决PHP无法实现多线程的问题
- 关于把struts2项目修改为开发模式,项目无法启动问题说明
- 关于singleTask模式无法收到intent传值问题的解决
- 关于RecyclerView实现瀑布流,上下滑动时item之间互换位置的问题
- 关于虚拟机与克隆虚拟机之间无法相互ping通的问题解决方案
- 关于在 Windows 和 VMware workstation 之间实现共享目录的问题
- 关于:“无法序列化会话状态。在“StateServer”或“SQLServer”模式下,ASP.NET 将序列化会话状态对象,因此不允许使用无法序列化的对象或 MarshalByRef 对象。如果自定义会话状态存储在“Custom”模式下执行了类似的序列化,则适用同样的限制。”的问题
- 关于openstack部分计算节点无法实现热迁移问题描述
- 关于cas server无法通过session持久化方式实现集群的问题
- 如何解决PHP无法实现多线程的问题
- 关于实现多线程的相关问题
- 关于多线程的经典问题——生产者消费者,不能实现循环工作。
- 关于使用图片轮播插件无法实现效果的问题
- 关于Virtualbox网络设置了解NAT模式后无法SSH连接的问题
- 关于crontab无法实现以秒为单位的计划任务的问题
- 巧妙解决PHP无法实现多线程的问题
- 【黑马程序员】关于多线程聊天室中出现的“由于其他线程拥有此对象,因此调用线程无法对其进行访问”问题的探究
- ubuntu 关于拯救模式下!!文件只读,无法修改的问题
- 关于UE4.12打包后无法切换到VR模式的问题
- 关于vs中项目之间无法引用的问题