您的位置:首页 > 其它

懒汉式单例模式的线程安全问题

2015-07-11 09:24 316 查看
所谓线程不安全实际上就是一段代码在同一时间被两个线程同时执行,导致运行结果与单个线程运行结果不相同。如下面提到的if 判断语句。

新建一个单例模式类和一个多线程测试类

<span style="font-size:14px;">public class Test24 implements Runnable {
public void run() {
System.out.println(TestSingleton.getInstance());
}

public static void main(String[] args) {
Test24 test1 = new Test24();
Test24 test2 = new Test24();
Thread thread1 = new Thread(test1);
Thread thread2 = new Thread(test2);

thread1.start();
thread2.start();
}
}

class TestSingleton {
private static TestSingleton testSingleton;

private TestSingleton() {
System.out.println("建新的对象");
}

public static TestSingleton getInstance() {
if (testSingleton == null) {
testSingleton = new TestSingleton();
}
return testSingleton;
}
}</span>
执行后发现会产生两个新的对象。控制台打印:

<span style="font-size:14px;">建新的对象
建新的对象
com.TestSingleton@328d5485
com.TestSingleton@5ca801b0</span>


说明有线程并发访问安全问题,获取的不是同一个实例

解决方案(1):使用同步锁机制,最简单的是在getInstance()方法上加synchronized关键字

<span style="font-size:14px;">public static synchronized TestSingleton getInstance() {
if (testSingleton == null) {
testSingleton = new TestSingleton();
}
return testSingleton;
}</span>
对于这种方式,有人觉得在多并发的情况下,每次获取实例都要判断锁,效率比较低下,所以就有人想出了这样的办法,双重判断实例,这种大大减少判断同步锁的次数了。所以实际使用中可以推广。

代码如下:

<span style="font-size:14px;">	public static TestSingleton getInstance() {
/*
* 如果第一个线程获取到了单例的实例对象, 后面的线程再获取实例的时候不需要进入同步代码块中了
*/
if (testSingleton == null) {
// 同步代码块用的锁是单例的字节码文件对象,且只能用这个锁
synchronized (TestSingleton.class) {
if (testSingleton == null) {
testSingleton = new TestSingleton();
}
}
}
return testSingleton;
}</span>


解决方案(2):改恶汉式单例为懒汉式单例

<span style="font-size:14px;">class TestSingleton {
private static TestSingleton testSingleton=new TestSingleton();

private TestSingleton() {
System.out.println("建新的对象");
}

public static TestSingleton getInstance() {
return testSingleton;
}
}</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: