2023年11月29日发(作者:)
JDK源码——单例模式
JDK源码中单例模式的应⽤
1、Runtime类
Runtime类封装了Java运⾏时的环境。每⼀个java程序实际上都是启动了⼀个JVM进程,那么每个JVM进程都是对应这⼀个Runtime实例,此实例是
由JVM为其实例化的。每个 Java 应⽤程序都有⼀个 Runtime 类实例,使应⽤程序能够与其运⾏的环境相连接。
由于Java是单进程的,所以,在⼀个JVM中,Runtime的实例应该只有⼀个。所以应该使⽤单例来实现。
1 public class Runtime {
2 private static Runtime currentRuntime = new Runtime();
3
4 public static Runtime getRuntime() {
5 return currentRuntime;
6 }
7 private Runtime() {}
8 }
View Code
以上代码为JDK中Runtime类的部分实现,是饿汉式单例模式。在该类第⼀次被classloader加载的时候,实例就被创建出来了。⼀般不能实例化⼀个
Runtime对象,应⽤程序也不能创建⾃⼰的 Runtime 类实例,但可以通过 getRuntime ⽅法获取当前Runtime运⾏时对象的引⽤。
验证:
1 Runtime r1 = time();
2 Runtime r2 = time();
3 n(r1 == r2);
View Code
运⾏结果:
true
2、t#getDefaultToolkit()
懒汉式单例。不需要事先创建好,只要在第⼀次真正⽤到的时候再创建就可以了。因为很多时候并不常⽤Java的GUI和其中的对象。如果使⽤饿汉单
例的话会影响JVM的启动速度。
1 public abstract class Toolkit {
2
3 private static Toolkit toolkit;
4
5 public static synchronized Toolkit getDefaultToolkit() {
6 if (toolkit == null) {
7 ileged(
8 new egedAction
9 public Void run() {
10 Class> cls = null;
11 String nm = perty("t");
12 try {
13 cls = e(nm);
14 } catch (ClassNotFoundException e) {
15 ClassLoader cl = temClassLoader();
16 if (cl != null) {
17 try {
18 cls = ass(nm);
19 } catch (final ClassNotFoundException ignored) {
20 throw new AWTError("Toolkit not found: " + nm);
21 }
22 }
23 }
24 try {
25 if (cls != null) {
26 toolkit = (Toolkit)tance();
27 if (less()) {
28 toolkit = new HeadlessToolkit(toolkit);
29 }
30 }
31 } catch (final InstantiationException ignored) {
32 throw new AWTError("Could not instantiate Toolkit: " + nm);
33 } catch (final IllegalAccessException ignored) {
34 throw new AWTError("Could not access Toolkit: " + nm);
35 }
36 return null;
37 }
38 });
39 loadAssistiveTechnologies();
40 }
41 return toolkit;
42 }
43 }
View Code
以上代码是Toolkit类的单例实现。这⾥类加载时只静态声明了私有toolkit并没有创建Toolkit实例对象,延迟加载加快了JVM启动速度。单例模式作为⼀
种创建模式,在依赖加载的时候应⽤了另⼀种创建对象的⽅式,不是new新的对象,因为Toolkit本⾝是个抽象类不能实例化对象,⽽是通过反射机制
加载类并创建新的实例。
3、csEnvironment#getLocalGraphicsEnvironment()
1 public abstract class GraphicsEnvironment {
2 private static GraphicsEnvironment localEnv;
3 public static synchronized GraphicsEnvironment getLocalGraphicsEnvironment() {
4 if (localEnv == null) {
5 localEnv = createGE();
6 }
7 return localEnv;
8 }
9
10 private static GraphicsEnvironment createGE() {
11 GraphicsEnvironment ge;
12 String nm = ileged(new GetPropertyAction("csenv", null));
13 try {
14 Class
15 try {
16 geCls = (Class
17 } catch (ClassNotFoundException ex) {
18 ClassLoader cl = temClassLoader();
19 geCls = (Class
20 }
21 ge = tance();
22 if (isHeadless()) {
23 ge = new HeadlessGraphicsEnvironment(ge);
24 }
25 } catch (ClassNotFoundException e) {
26 throw new Error("Could not find class: "+nm);
27 } catch (InstantiationException e) {
28 throw new Error("Could not instantiate Graphics Environment: "
29 + nm);
30 } catch (IllegalAccessException e) {
31 throw new Error ("Could not access Graphics Environment: "
32 + nm);
33 }
34 return ge;
35 }
36 }
View Code
这⾥类加载时只静态声明了私有localEnv并没有创建实例对象。在GraphicsEnvironment类被第⼀次调⽤时会创建该对象。这⾥的createGE()⽅法也是
通过反射的⽅式创建对象的。
总结:
(1)当⼀个类的对象只需要或者只可能有⼀个时,应该考虑单例模式。
(2)如果⼀个类的实例应该在JVM初始化时被创建出来,应该考虑使⽤饿汉式。
(3)如果⼀个类的实例不需要预先被创建,也许这个类的实例并不⼀定能⽤得上,也许这个类的实例创建过程⽐较耗费时间,也许就是真的没必要
提前创建。那么应该考虑懒汉式。


发布评论