1、饿汉式
- 优点:类加载的时候完成实例化,避免了线程同步问题
- 缺点:在类加载的时候就完成实例化,没有达到Lazy Loading的效果,如果该类未使用则造成了内存浪费
可以通过静态变量和静态代码块两种方式实现,效果一样
public class Singleton1 {
//方式1:通过静态变量方式创建
private static final Singleton1 INSTANCE = new Singleton1();
//方式2:通过静态代码块的方式,效果和方法1一样
// private static final Singleton1 INSTANCE;
//
// static {
// INSTANCE = new Singleton1();
// }
/**
* 私有的构造方法,防止产生多个对象
*/
private Singleton1() {
}
/**
* 通过该方法获得实例
*
* @return
*/
public static Singleton1 getInstance() {
return INSTANCE;
}
public void doSomething() {
}
}
可通过如下方式,在多个线程中创建多个单例对象,查看创建的对象hashCode是否相同判断是否为单例
Executor executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
//测试饿汉式单例
Singleton1 singleton1 = Singleton1.getInstance();
Singleton1 singleton2 = Singleton1.getInstance();
System.out.println(singleton1.hashCode() + "\t-----\t" + singleton2.hashCode());
}
});
}
打印结果如下,不同线程下的Singleton1对象都是同一个HashCode,表示是全局单例
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2007961061 ----- 2007961061
2、懒汉式-线程不安全
- 优点:做到了懒加载
- 缺点:多线程使用的时候会产生多个实例,实际开发中不要使用这种方案
public class SingLeton2 {
private static SingLeton2 INSTANCE;
private SingLeton2() {
}
public static SingLeton2 getInstance() {
if (INSTANCE == null) {
INSTANCE = new SingLeton2();
}
return INSTANCE;
}
}
多线程创建此单例hashcode如下,存在hashCode不一致的问题,所有没有做到全局单例
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1523178316 ----- 1523178316
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
1337000531 ----- 1337000531
3、懒汉式 线程安全
- 优点:加了同步,线程安全
- 缺点:效率太低,开发中不推荐使用这种写法
public class Singleton3 {
private static Singleton3 INSTANCE;
private Singleton3() {
}
public static synchronized Singleton3 getINSTANCE() {
if (INSTANCE == null) {
INSTANCE = new Singleton3();
}
return INSTANCE;
}
}
下面这种方式,虽然加锁了但是还是存在线程不安全的问题,同一时刻不同的线程走到if(instance==null)这一步时,还是会创建不同的对象
//方式二 线程不安全
static class Singleton7{
private static Singleton7 instance;
private Singleton7(){}
public static Singleton7 getInstance() {
if(instance==null){
synchronized (Singleton7.class){
instance=new Singleton7();
}
}
return instance;
}
}
4、双重检查
- 优点:线程安全,延迟加载,效率高
- 开发中推荐使用这种方案
public class Singleton4 {
private static volatile Singleton4 instance;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (instance == null) {
synchronized (Singleton4.class) {
if (instance == null) {
instance = new Singleton4();
}
}
}
return instance;
}
}
5、静态内部类
- 优点:线程安全,也做到了懒加载,开发中推荐使用
public class Singleton5 {
private Singleton5() {
}
private static class Singleton5Instance {
private static final Singleton5 INSTANCE = new Singleton5();
}
public static Singleton5 getInstance() {
return Singleton5Instance.INSTANCE;
}
}
6、枚举方式创建单例
- <<Effective Java>>推荐使用这种方式创建单例,项目中推荐使用
public enum Singleton6 {
INSTANCE;
public void doSomething() {
System.out.println("枚举创建");
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
网友评论