单例模式代码示例
/**
单例模式(懒汉模式)
*/
public class Singleton {
private Singleton() {} //私有化构造方法
private static Singleton instance;
public static Singleton getInstance() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null == instance)
instance = new Singleton();
return instance;
}
}
使用多线程测试线程安全问题
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MutiTreadMain {
public static void main(String[] args) {
ExecutorService threadpool = Executors.newFixedThreadPool(20);
for(int i = 0 ; i <20 ; i++) {
threadpool.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+":"+Singleton.getInstance());
}
});
}
}
}
结果显而易见懒汉模式是不安全的
为了解决线程不安全问题
方法一:使用synchronized方法同步方法
public class Singleton {
private Singleton() {} //私有化构造方法
private static Singleton instance;
public static synchronized Singleton getInstance() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null == instance)
instance = new Singleton();
return instance;
}
}
这样做虽然可以解决问题但 synchronized同步方法会带来极大的cpu开销
方法2 使用synchronized同步代码块只同步初始话实例部分
public class Singleton {
private Singleton() {} //私有化构造方法
private static Singleton instance;
public static Singleton getInstance() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null == instance)
{
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
}
这样做实际没有解决线程安全性问题,如果线程A和线程B同时访问getInstance方法的synchronized (Singleton.class)位置
当A实例化了后 ,B线程得到cpu会再次实例导致两个对象不一致
所以需要做双重检测加锁
public class Singleton {
private Singleton() {} //私有化构造方法
private static Singleton instance;
public static Singleton getInstance() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null == instance)
{
synchronized (Singleton.class) {
if(null == instance)
instance = new Singleton();
}
}
return instance;
}
}
最后的问题
jvm重排序
解决办法 添加关键字volatile 修饰成员变量
public class Singleton {
private Singleton() {} //私有化构造方法
private static volatile Singleton instance;
public static Singleton getInstance() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null == instance)
{
synchronized (Singleton.class) {
if(null == instance)
instance = new Singleton();
}
}
return instance;
}
}