说起单例设计模式因该很多人都不陌生,按理说只有接触过java的都应该知道这个设计模式,但是你真的会写吗?还是说只会懒汉式和饿汉式?其实日常工作中随便掌握一种就已经可以了,但是我们身为java程序员应该不断的学习,即使用不到但是也要来了解以下,接下来我就来给你们写单例的八种写法,其中只有四种是能有并且没有问题的,其他的都有问题
写法一:传统的饿汉式
class Singleton01{
private static final Singleton01 INSTANCE = new Singleton01();
private Singleton01(){}
public static Singleton01 getInstance(){
return INSTANCE;
}
}
public class Main{
public static void main(String[] args){
Singleton01 instance = Singleton01.getInstance();
}
}
这种就是传统的饿汉式,相信你们并不陌生,这种其实已经很好了,在工作中就写这种也没有任何问题,但是会有些人觉得这个太浪费资源,因为只要去加载这个类,那么这个实例就会创建
写法二:有问题的写法,懒汉式
class Singleton02{
private static volatile Singleton02 instance;
private Singleton02(){}
public static Singleton02 getInstance(){
if(instance == null){
instance = new Singleton02();
}
return instance;
}
}
public class Main{
public static void main(String[] args){
Singleton02 instance = Singleton02.getInstance();
}
}
这种写法在多线程的情况下不能保证只有一个实例,所以这是有问题的
写法三:加锁,懒汉式
class Singleton03{
private static volatile Singleton03 instance;
private Singleton03(){}
public static synchronized Singleton03 getInstance(){
if(instance == null){
instance = new Singleton03();
}
return instance;
}
}
public class Main{
public static void main(String[] args){
Singleton03 instance = Singleton03.getInstance();
}
}
这种写法每次去拿对象的时候都会加锁,我们都知道加锁会导致效率变慢
写法四:判断加锁,懒汉式
class Singleton04{
private static Singleton04 instance;
private Singleton04(){}
public static volatile Singleton04 getInstance(){
if(instance == null){
synchronized(Singleton04.class){
instance = new Singleton04();
}
}
return instance;
}
}
public class Main{
public static void main(String[] args){
Singleton04 instance = Singleton04.getInstance();
}
}
这种写法虽然对比上面那中效率高了些,但是在多线程的响应下,他还是不能保证只有一个实例
写法五:双重判断加锁,懒汉式
class Singleton05{
private static volatile Singleton05 instance;
private Singleton05(){}
public static Singleton05 getInstance(){
if(instance == null){
synchronized(Singleton05.class){
if(instance == null){
instance = new Singleton05();
}
}
}
return instance;
}
}
这种写法也很常见,这样只要有一个线程将这个实例创建出来了,就不会执行下面的加锁的那段代码,所以效率还是可以的,只有第一次拿的时候会稍微慢一点,因为第一次要创建对象
写法六:静态内部类的方法
public class Singleton06 {
private static class SingletonInstance{
private static final Singleton06 INSTANCE = new Singleton06();
}
private Singleton06() {}
public static Singleton06 getInstance() {
return SingletonInstance.INSTANCE;
}
}
这种方式已经够很完美了,通过内部类的方式来保证这个单例,这种写法可能看到过的人就比较少了
写法7:枚举单例
public enum Singleton07 {
INSTANCE;
}
这种才是最最最完美的,也是最简单的,下面还有一种,这种应该写在第二种的,但是由于我个人给忘了,所以就写到最下面吧,
写法八:通过静态代码块,饿汉式
public class Singleton08 {
private static final Singleton08 INSTANCE;
static {
INSTANCE = new Singleton08();
}
private Singleton08() {}
public static Singleton08 getInstance() {
return INSTANCE;
}
}
这种跟第一种是一样的,也就没有必要说了,看到这里你才是真正的了解这个单例模式了。不加volatile可能在指令重排的时候出问题