Code Bye

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

单例模式:保证一个类仅有一个势力,并提供一个访问它的全局访问点,在编程实现的时候,我想让两个线程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次调用……”
希望尽快得到大家的解答,谢谢。。。

大家快来帮忙啊!
帮帮忙啊!为何没有人呢???
真的没人么???

10分
我测试了一下发现,是你的Thread.sleep(1000)的问题,如下图,当ss1进入createSingletonInstance函数时,i会变为1,会因为sleep函数而停在这里一会儿,这个时候ss2就进入了createSingletonInstance函数,i还是会加1,即这个时候i是2.而且这个时候两个线程都还在sleep函数这一块,没有往下执行,所以之后两个线程往下执行之后,两个语句输出来的就都是i=2的输出语句。这样解释你应该理解了吧

但是我给函数createSingletoninstance加锁了呀,同一时刻应该改只有一个线程可以访问啊,为何线程ss1,ss2都可以调用该函数?
引用 4 楼 software_gemeng 的回复:

我测试了一下发现,是你的Thread.sleep(1000)的问题,如下图,当ss1进入createSingletonInstance函数时,i会变为1,会因为sleep函数而停在这里一会儿,这个时候ss2就进入了createSingletonInstance函数,i还是会加1,即这个时候i是2.而且这个时候两个线程都还在sleep函数这一块,没有往下执行,所以之后两个线程往下执行之后,两个语句输出来的就都是i=2的输出语句。这样解释你应该理解了吧

但是我给函数createSingletoninstance加锁了呀,同一时刻应该改只有一个线程可以访问啊,为何线程ss1,ss2都可以调用该函数?


10分
对于这个问题,首先要了解对象锁,你每次创建了新的对象,就会有新的对象锁,每次线程使用的都是新的对象。试试这样写:
TestSingleton s = new TestSingleton();
		Thread t1 = new Thread(s, "ss1");
		Thread t2 = new Thread(s, "ss2");
		Thread t3 = new Thread(s, "ss3");
		t1.start();
		t2.start();
		t3.start();

这样就是多个线程调用一个对象的同步方法


10分
最基本的都不懂,你对对象的方法加了锁 这个意思就是同一个实例会互斥,你new了两个对象 怎么互斥啊 哥!
引用 8 楼 liudehuas5 的回复:

最基本的都不懂,你对对象的方法加了锁 这个意思就是同一个实例会互斥,你new了两个对象 怎么互斥啊 哥!

谢谢啊。刚刚才找到问题的本质。

引用 7 楼 javaliuliu 的回复:

对于这个问题,首先要了解对象锁,你每次创建了新的对象,就会有新的对象锁,每次线程使用的都是新的对象。试试这样写:

TestSingleton s = new TestSingleton();
		Thread t1 = new Thread(s, "ss1");
		Thread t2 = new Thread(s, "ss2");
		Thread t3 = new Thread(s, "ss3");
		t1.start();
		t2.start();
		t3.start();

这样就是多个线程调用一个对象的同步方法

谢谢啊,刚刚才找到问题的本质


10分
方法前加锁是保证不会有两个线程同时执行该类的方法,你的这个情况类本身就是一个线程,没有什么实际意义

i是你这个线程自身的成员变量,如果你想让两个线程互斥访问这个成员变量,在这个成员变量上加锁sychronized(i)

public static void main(String[] args) {
     TestSingleton ts = new TestSingleton();
        Thread t1 = new Thread(ts, “ss1”);
        Thread t2 = new Thread(ts, “ss2”);
        t1.start();
        t2.start();
    }
谢谢大伙儿啊

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明关于单例模式和多线程之间无法实现的问题