您的位置:首页 > 其它

关于单例模式和多线程之间无法实现的问题

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_gemengjavaliuliuliudehuas5的解答

更改后代码如下: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在全局是互斥的。

终于搞明白了。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐