时间:2021-05-20
懒汉模式与饿汉模式
懒汉模式就是懒加载,用到的时候去加载,存在线程安全问题,需要手动地加锁控制。它的优点是类加载的速度比较快,按需加载,节省资源。
饿汉模式就是在类加载的时候会创建出实例。它天生就不存在线程安全问题。但是类加载的速度会变慢且耗费资源。
懒汉模式-单重检查
示例代码如下:
public class LazySingleton { private static LazySingleton singletoninstance = null; private Object data = new Object();//私有化构造方法 private LazySingleton(){ }//加锁访问 public static synchronized LazySingleton getInstance(){ if(singletoninstance == null){ singletoninstance = new LazySingleton(); } return singletoninstance; } public Object getData() { return data; } public void setData(Object data) { this.data = data; }}测试代码如下:
public class TestThread extends Thread { @Override public void run() { LazySingleton instance = LazySingleton.getInstance(); System.out.println(instance.getData()); }}public static void main(String[] args) { for(int i =0;i < 10;i++){ TestThread t = new TestThread(); t.start(); } }}运行结果如下:
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
java.lang.Object@306d3b64
打印出同一个object对象,表明是从同一个LazySingleton对象中获取的数据。
但是上述代码存在一个显著的问题:多个线程同时访问getInstance()方法都是排队式的,即使该instance已经被创建的情况下。然而,如果该instance已经被创建,是可以支持并发访问的。需要对锁的控制细粒度化。
懒汉模式-双重检查
public class LazySingleton {//声明为volatile变量 private static volatile LazySingleton singletoninstance = null; private Object data = new Object(); private LazySingleton(){ } public static synchronized LazySingleton getInstance(){ if(singletoninstance == null){ synchronized (LazySingleton.class) { //这个第二重的的检查是必要的 if(singletoninstance == null) singletoninstance = new LazySingleton(); } } return singletoninstance; } public Object getData() { return data; } public void setData(Object data) { this.data = data; }}第二重检查是为了防止:
线程A发现instance未被创建,于是申请锁,进入临界区创建instance;于此同时另一个线程也发现instance未被创建,于是也要申请锁去创建instance,问题就这样发生了。而且,这个instance变量要被声明为volatile,也就是其中一个线程对它就行修改之后(也就是实例化),这一修改立马对其他线程可见,避免了无谓的等待。
检查代码同上,运行结果同上。
饿汉模式
public class HungerSingleton { private static final HungerSingleton singletoninstance = new HungerSingleton(); private Object data = new Object(); private HungerSingleton(){ } public static HungerSingleton getInstance(){ return singletoninstance; } public Object getData() { return data; } public void setData(Object data) { this.data = data; }}在加载该类的时候就立马去实例化instance,不存在线程安全问题(由jvm保证线程安全问题),但是存在资源浪费、加载速度慢的问题。
检查代码同上,运行结果同上。
Holder模式
就是利用一个静态内部类来实现instance的实例化。这里利用了静态内部类的一个特性:该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
public class HolderSingleton { private Object data = new Object(); private HolderSingleton(){ } private static class InnerClass{ private static HolderSingleton singletoninstance = new HolderSingleton(); } public static HolderSingleton getInstance(){ return InnerClass.singletoninstance; } public Object getData() { return data; } public void setData(Object data) { this.data = data; }}测试代码同上,运行结果同上。
在加载InnerClass的时候才会去实例化这个instance,实现了延迟加载,并且同饿汉模式一样,由jvm保证线程安全。这种方法值得推荐。
应用场景:
在整个系统中,只允许共用一个实例的类适合用单例模式来实现,比如:
网站的计数器,只允许存在一个计数器实例;
线程池,只允许存在一个线程池对象;
连接池,只允许存在一个连接池对象;
知识点扩充:
1.为什么要使用单例模式?
在我们日常的工作中,很多对象通常占用非常重要的系统资源,比如:IO处理,数据库操作等,那我们必须要限制这些对象只有且始终使用一个公用的实例,即单例。
2.单例模式的实现方式
构造函数私有化,防止其他类生成唯一公用实例外的实例。且单例类应该被定义为final,也就是说单例类不能被继承,因为如果允许继承那子类就都可以创建实例,违背了类唯一实例的初衷。
类中一个静态变量来保存单实例的引用。
一个共有的静态方法来获取单实例的引用。
3.单例模式的UML类图
4.单例模式的经典实现方式
以上就是本次小编结合多篇整理的相关内容,希望能够帮助到大家。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
java单例模式的实例详解概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。 单例模式有一下特点:
java单例模式直接讲实现单例模式的两种方法:懒汉式和饿汉式,单例模式的概念自己上网搜吧这里就不讲了!这里会涉及到java中的jvm,如果你没有这方面的知识,我
java中设计模式(多例)的实例详解多例:单例设计模式的变形,可以看成是一个缓存池的单例,而缓存池里面可以存多个数据实例代码://单例+缓存---没有控制池大小
在设计模式的策略模式中,需要动态加载程序集信息,本文通过一个简单的实例,来讲解动态加载Dll需要的知识点。涉及知识点:AssemblyName类,完整描述程序集
我们今天来聊下如何做实时通讯(先给知识点,实现原理,最后给出实现实时通信的具体代码--使用工具androidstudio)现在先说下用到的知识点:java的so