java单例模式

单例设计模式:Spring中的Bean默认都是单例的。

概念

全世界就只要一个---在整个java程序中,只有这个类的一个实例

比如Student a = new Student(); 就是Student类只创建这一个实例,只能有这一个对象存在

主要解决:一个全局使用的类频繁地创建与销毁。在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)

何时使用:当您想控制实例数目,节省系统资源的时候。

关键代码:构造函数是私有的。

1、为了保证只有一个对象,不能new对象,所以设置构造方法私有。

2、只能通过方法或者属性获取对象,如果通过属性获取,这个属性是可以修改的,所以属性只能

是私有的。所以只能通过方法获取。

3、由于我们不能new对象,所以获取对象的方法定是静态的。属性也得是静态的,因为不是静态的,静态的方法访问不到

缺点:没有接口,不能继承,与单一 职责原则冲突,一 个类应该只关心内部逻辑, 而不关心外面怎么样来实例化。

使用场景:

  • 1、要求生产唯一序列号。

  • 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。

  • 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。

枚举:对象固定,私有构造器

饿汉

类加载后一开始就会创建对象

缺点就是占内存

java单例模式_第1张图片 

懒汉模式

需要的时候才会去创建对象

好处:节省内存 坏处用的时候才创建稍微有点慢

线程不安全,当创建了100个线程,调用getInstance方法时,可能会有多个线程同时看到没有new,就会执行多次new,调用多次构造方法(也就是会进行多次初始化)

线程安全 给getInstance方法加synchronize锁

java单例模式_第2张图片

 

双重校验锁--安全的懒汉式

我们可以选择不给getInstance方法加synchronize锁,而是在这个方法里面去进行加synchronize锁,因为方法锁的范围太广,其他线程阻塞的范围就大,时间就长。

双锁是懒汉为了解决线程安全演变来的

当多线程调用getInstance,不知道是不是第一次调用,有没有创建对象,所以要判断一下属性是否为空

为空需要创建对象,但是在多线程的情况下,访问这个方法的情况下,多个线程可能会创建多个对象,就不是单例了

所以在判断是不是为空后,需要给这个对象加synchronize锁。

假设第一个线程执行完,接下来的线程就会来进行竞争锁,它还是要继续判断是否为空,不为空,直接return

synchroniz不能防止指令重排序,instance = new Instance () ;可能会发生指令重排序,就是另一个线程会访问到Instance 仍然为空,再次进入到第一个if循环

类属性加volatile的原因:第一个线程加锁之后创建了对象,能够让其他线程及时发现 instance 不是空了,这样其他线程就不用进入第一层判断了,加快了程序速度;如果没有加volatile,不能防止指令重排序,可能对象创建了,但是句柄的地址没有传给属性,判断时还是空,这样就需要继续走第一层if。

java单例模式_第3张图片

 

你可能感兴趣的:(单例模式,java,开发语言)