Java完美的单例
public class Singleton {
public volatile static Singleton instance;
public Singleton() {
}
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
return new Singleton();
}
// return instance;
}
}
return instance;
}
}
这是一个完美的单例,具体分析请阅读下面的文章。
简单的饿汉式单例模式
public class Singleton {
public static Singleton instance;
public Singleton() {
}
public static Singleton getInstance(){
if (instance == null){
return new Singleton();
}
return instance;
}
}
在单线程的环境下,该模式是可以正常运行的。但是在多线程高并发的环境下,就会出现问题,当大量的线程来访问时,此时并没有实例化,大量的线程就会去创建实例,导致创建多个实例,破坏了单例模式的目的。此时的解决方法是加锁。
public class Singleton {
public static Singleton instance;
public Singleton() {
}
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
return new Singleton();
}
}
return instance;
}
}
加锁之后,看似在创建实例的代码时同步的。但是并不是这样的,大量线程判断实例为空后,仍会执行同步代码块,创建多个实例,也是不行的。那么将锁范围扩大。
public class Singleton {
public static Singleton instance;
public Singleton() {
}
public static Singleton getInstance(){
synchronized (Singleton.class){
if (instance == null){
return new Singleton();
}
return instance;
}
}
}
此时已经解决了多线程的并发问题,但是性能低下,每个线程都直接同步执行代码块,都需要排队去判断单例是否存在,其实只需要一个线程创建了单例,其他线程只需获取就行了。那么在外面在加上一个判断。
public class Singleton {
public static Singleton instance;
public Singleton() {
}
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
return new Singleton();
}
// return instance;
}
}
return instance;
}
}
这种方法也叫做双重锁模式,解决了上一种的性能问题。但是还存在一个小问题就是指令重排。在创建对象一般分为3步:1.分配内存空间;2.对象初始化;3.指向被分配的空间。指令重排有可能将2.3步进行重排,导致对象半初始化,一个线程拿去这个对象,可能造成空指针异常,那么就需要加上volatile来防止指令重排。
public class Singleton {
public volatile static Singleton instance;
public Singleton() {
}
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
return new Singleton();
}
// return instance;
}
}
return instance;
}
}
此时的单例在保证多线程环境的安全,还可以保持高性能。