单例设计模式

单例设计模式

单例设计模式,即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式。
例如:代表JVM运行环境的Runtime类

要点:

  1. 某个类只能有一个实例;

    • 构造器私有化
  2. 是它必须自行创建这个实例;

    • 含有一个该类的静态变量来保存这个唯一的实例
  3. 是它必须自行向整个系统提供这个实例;

    • 对外提供获取该实例对象的方式:(1)直接暴露(2)用静态变量的get方法获取

饿汉式

直接创建对象,不存在线程安全问题

缺点:不管是否需要这个对象,都会创建。

方式1:直接实例化饿汉式

好处:简洁直观,外部可以直接获取这个实例。

1
2
3
4
5
6
7
public class Singleton1 {
public static final Singleton1 SINGLETON = new Singleton1();

private Singleton1(){

}
}

方式2:枚举式

最简洁的方式:枚举类型,表示该类型的对象是有限的几个,我们可以限定为一个,就成了单例。

1
2
3
public enum Singleton2 {
SINGLETON
}

方式3:静态代码块饿汉式

适合在实例化时需要进行复杂的初始化操作时使用,比如初始化实例时需要加载配置文件中的参数作为实例变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Singleton3 {
private static Singleton3 SINGLETON;
private String info;

static{
Properties properties = new Properties();

try {
// 配置文件加载之后会在编译目录里面,通过获取字节码加载器对象取到编译目录中的文件。
properties.load(Singleton3.class.getClassLoader().getResourceAsStream("xyz/yuzh/interview/singleton/info.properties"));
} catch (IOException e) {
}

SINGLETON = new Singleton3(properties.getProperty("info"));
}

private Singleton3(String info){
this.info = info;
}

public static Singleton3 getInstance(){
return SINGLETON;
}

@Override
public String toString() {
return "Singleton3{" +
"info='" + info + '\'' +
'}';
}
}

懒汉式

延迟创建对象

方式1:线程不安全

单线程下是线程安全的,但是多线程下是不安全的。

1
2
3
4
5
6
7
8
9
10
11
12
public class Singleton4 {
private static Singleton4 singleton;
private Singleton4() {

}
public static Singleton4 getInstance() {
if (singleton == null) {
singleton = new Singleton4();
}
return singleton;
}
}

用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Singleton4Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*Callable<Singleton4> callable = new Callable<Singleton4>() {
@Override
public Singleton4 call() throws Exception {
return Singleton4.getInstance();
}
};*/

Callable<Singleton4> callable = () -> {
return Singleton4.getInstance();
};

ExecutorService es = Executors.newFixedThreadPool(5);
Future<Singleton4> future1 = es.submit(callable); // 提交一个任务
Future<Singleton4> future2 = es.submit(callable); // 再提交一个任务
es.shutdown();

Singleton4 s1 = future1.get();
Singleton4 s2 = future2.get();

System.out.println(s1 == s2);
}
}

结果:

false

方式2:线程安全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton5 {
private static Singleton5 singleton;

private Singleton5() {

}

public static Singleton5 getInstance() {
if (singleton == null) {
synchronized (Singleton5.class) {
if (singleton == null) {
singleton = new Singleton5();
}
}
}
return singleton;
}
}

方式3:静态内部类形式,线程安全

最简洁的方式,在内部类被加载和初始化时,才创建 SINGLETON 实例对象。静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的。因为是在内部类加载和初始化时,创建的,因此是线程安全的

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton6{
private Singleton6() {

}

public static class Inner{
private static final Singleton6 SINGLETON = new Singleton6();
}

public static Singleton6 getInstance(){
return Inner.singleton;
}
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×