Java 单例模式讲解和代码示例

简介: Java 单例模式讲解和代码示例

使用示例许多开发者将单例模式视为一种反模式 因此它在 Java 代码中的使用频率正在逐步减少

尽管如此 Java 核心程序库中仍有相当多的单例示例

  • java.lang.Runtime#getRuntime()
  • java.awt.Desktop#getDesktop()
  • java.lang.System#getSecurityManager()

识别方法单例可以通过返回相同缓存对象的静态构建方法来识别


01基础单例(单线程)


实现一个粗糙的单例非常简单 你仅需隐藏构造函数并实现一个静态的构建方法即可

Singleton.java: 单例

package refactoring_guru.singleton.example.non_thread_safe;
public final class Singleton {
    private static Singleton instance;
    public String value;
    private Singleton(String value) {
        // The following code emulates slow initialization.
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        this.value = value;
    }
    public static Singleton getInstance(String value) {
        if (instance == null) {
            instance = new Singleton(value);
        }
        return instance;
    }
}
DemoSingleThread.java: 客户端代码
package refactoring_guru.singleton.example.non_thread_safe;
public class DemoSingleThread {
    public static void main(String[] args) {
        System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
                "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
                "RESULT:" + "\n");
        Singleton singleton = Singleton.getInstance("FOO");
        Singleton anotherSingleton = Singleton.getInstance("BAR");
        System.out.println(singleton.value);
        System.out.println(anotherSingleton.value);
    }
}

OutputDemoSingleThread.txt: 执行结果

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)
RESULT:
FOO
FOO

02基础单例(多线程)

相同的类在多线程环境中会出错 多线程可能会同时调用构建方法并获取多个单例类的实例

Singleton.java: 单例

package refactoring_guru.singleton.example.non_thread_safe;
public final class Singleton {
    private static Singleton instance;
    public String value;
    private Singleton(String value) {
        // The following code emulates slow initialization.
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        this.value = value;
    }
    public static Singleton getInstance(String value) {
        if (instance == null) {
            instance = new Singleton(value);
        }
        return instance;
    }
}
DemoMultiThread.java: 客户端代码
package refactoring_guru.singleton.example.non_thread_safe;
public class DemoMultiThread {
    public static void main(String[] args) {
        System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
                "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
                "RESULT:" + "\n");
        Thread threadFoo = new Thread(new ThreadFoo());
        Thread threadBar = new Thread(new ThreadBar());
        threadFoo.start();
        threadBar.start();
    }
    static class ThreadFoo implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("FOO");
            System.out.println(singleton.value);
        }
    }
    static class ThreadBar implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("BAR");
            System.out.println(singleton.value);
        }
    }
}

OutputDemoMultiThread.txt: 执行结果

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)
RESULT:
FOO
BAR

03采用延迟加载的线程安全单例


为了解决这个问题 你必须在创建首个单例对象时对线程进行同步

Singleton.java: 单例

package refactoring_guru.singleton.example.thread_safe;
public final class Singleton {
    // The field must be declared volatile so that double check lock would work
    // correctly.
    private static volatile Singleton instance;
    public String value;
    private Singleton(String value) {
        this.value = value;
    }
    public static Singleton getInstance(String value) {
        // The approach taken here is called double-checked locking (DCL). It
        // exists to prevent race condition between multiple threads that may
        // attempt to get singleton instance at the same time, creating separate
        // instances as a result.
        //
        // It may seem that having the `result` variable here is completely
        // pointless. There is, however, a very important caveat when
        // implementing double-checked locking in Java, which is solved by
        // introducing this local variable.
        //
        // You can read more info DCL issues in Java here:
        // https://refactoring.guru/java-dcl-issue
        Singleton result = instance;
        if (result != null) {
            return result;
        }
        synchronized(Singleton.class) {
            if (instance == null) {
                instance = new Singleton(value);
            }
            return instance;
        }
    }
}

DemoMultiThread.java: 客户端代码

package refactoring_guru.singleton.example.thread_safe;
public class DemoMultiThread {
    public static void main(String[] args) {
        System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
                "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
                "RESULT:" + "\n");
        Thread threadFoo = new Thread(new ThreadFoo());
        Thread threadBar = new Thread(new ThreadBar());
        threadFoo.start();
        threadBar.start();
    }
    static class ThreadFoo implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("FOO");
            System.out.println(singleton.value);
        }
    }
    static class ThreadBar implements Runnable {
        @Override
        public void run() {
            Singleton singleton = Singleton.getInstance("BAR");
            System.out.println(singleton.value);
        }
    }
}

OutputDemoMultiThread.txt: 执行结果

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)
RESULT:
BAR
BAR
相关文章
|
1天前
|
Java 程序员 图形学
程序员教你用代码制作飞翔的小鸟--Java小游戏,正好拿去和给女神一起玩
《飞扬的小鸟》Java实现摘要:使用IntelliJ IDEA和JDK 16开发,包含小鸟类`Bird`,处理小鸟的位置、速度和碰撞检测。代码示例展示小鸟图像的加载、绘制与旋转。同时有`Music`类用于循环播放背景音乐。游戏运行时检查小鸟是否撞到地面、柱子或星星,并实现翅膀煽动效果。简单易懂,可直接复制使用。
|
1天前
|
Java Kotlin
java调用kotlin代码编译报错“找不到符号”的问题
java调用kotlin代码编译报错“找不到符号”的问题
16 10
|
1天前
|
前端开发 Java Spring
Java Web ——MVC基础框架讲解及代码演示(下)
Java Web ——MVC基础框架讲解及代码演示
11 1
|
1天前
|
设计模式 前端开发 网络协议
Java Web ——MVC基础框架讲解及代码演示(上)
Java Web ——MVC基础框架讲解及代码演示
6 0
|
1天前
|
Java
Java的取余如何编写代码
【5月更文挑战第9天】Java的取余如何编写代码
19 5
|
1天前
|
Java
代码实例演示Java字符串与输入流互转
代码实例演示Java字符串与输入流互转
|
1天前
|
存储 安全 Java
掌握8条泛型规则,打造优雅通用的Java代码
掌握8条泛型规则,打造优雅通用的Java代码
掌握8条泛型规则,打造优雅通用的Java代码
|
1天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
11 0
|
1天前
|
数据库连接
java+ssm+vue代码视频学习讲解
java+ssm+vue代码视频学习讲解
10 0
|
1天前
|
SQL 缓存 算法
优化你的Java代码:性能调优技巧
优化你的Java代码:性能调优技巧
13 0