转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10845530.html

一:静态内部类实现单例模式

  原理:通过一个静态内部类定义一个静态变量来持有当前类实例,在类加载时就创建好,在使用时获取。

  缺点:无法做到延迟创建对象,在类加载时进行创建会导致初始化时间变长。

public class SingletonInner {
private static class Holder {
private static SingletonInner singleton = new SingletonInner();
} private SingletonInner(){} public static SingletonInner getSingleton(){
return Holder.singleton;
}

二:饿汉模式

  原理:创建好一个静态变量,每次要用时直接返回。

  缺点:无法做到延迟创建对象,在类加载时进行创建会导致初始化时间变长。

public class SingletonHungry {

    private static SingletonHungry instance = new SingletonHungry();

    private SingletonHungry() {
} public static SingletonHungry getInstance() {
return instance;
}

三:懒汉模式

  原理:延迟创建,在第一次用时才创建,之后每次用到就返回创建好的。

  缺点:由于synchronized的存在,多线程时效率很低。

public class SingletonLazy {

    private static volatile SingletonLazy instance;

    private SingletonLazy() {
} public static synchronized SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}

四:双重校验锁懒汉模式

  原理:在getSingleton()方法中,进行两次null检查。这样可以极大提升并发度,进而提升性能。

public class Singleton {
private static volatile Singleton singleton = null;//使用valatile,使该变量能被所有线程可见 private Singleton(){} public static Singleton getSingleton(){
if(singleton == null){
synchronized (Singleton.class){//初始化时,加锁创建
if(singleton == null){//为避免在加锁过程中被其他线程创建了,再作一次非空校验
singleton = new Singleton();
}
}
}
return singleton;
}

五:上述4种方式实现单例模式的缺点

  1、反序列化对象时会破环单例

  反序列化对象时不会调用getXX()方法,于是绕过了确保单例的逻辑,直接生成了一个新的对象,破环了单例。

  解决办法是:重写类的反序列化方法,在反序列化方法中返回单例而不是创建一个新的对象。

public class Singleton implements java.io.Serializable {
public static Singleton INSTANCE = new Singleton(); protected Singleton() {
} //反序列时直接返回当前INSTANCE
private Object readResolve() {
return INSTANCE;
}
}

  2、在代码中通过反射机制,直接调用类的私有构造函数创建新的对象,会破环单例

  解决办法是:维护一个volatile的标志变量在第一次创建实例时置为false;重写构造函数,根据标志变量决定是否允许创建。

private static volatile  boolean  flag = true;
private Singleton(){
if(flag){
flag = false; //第一次创建时,改变标志
}else{
throw new RuntimeException("The instance already exists !");
}

六:枚举模式实现单例——将单例维护在枚举类中作为唯一实例

  原理:定义枚举类型,里面只维护一个实例,以此保证单例。每次取用时都从枚举中取,而不会取到其他实例。

public enum  SingletonEnum {
INSTANCE;
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}

  优点:

  1)使用SingletonEnum.INSTANCE进行访问,无需再定义getInstance方法和调用该方法。

  2)JVM对枚举实例的唯一性,避免了上面提到的反序列化和反射机制破环单例的情况出现:每一个枚举类型和定义的枚举变量在JVM中都是唯一的。 

    原因:枚举类型在序列化时仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象

      同时,编译器禁止重写枚举类型的writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。

  

  

Java单例模式的几种实现的更多相关文章

  1. Java 单例模式的七种写法

    Java 单例模式的七种写法 第一种(懒汉,线程不安全) public class Singleton { private static Singleton instance; private Sin ...

  2. 单例模式:Java单例模式的几种写法及它们的优缺点

    总结下Java单例模式的几种写法: 1. 饿汉式 public class Singleton { private static Singleton instance = new Singleton( ...

  3. java单例模式的几种写法比较

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  4. Java单例模式的6种写法

    在Java中,单例有很多种写法,面试时,手写代码环节,除了写算法题,有时候也会让手写单例模式,这里记录一下单例的几种写法和优缺点. 初级写法 懒汉式 饿汉式 双锁检验 内部类 枚举式 1.初级写法 p ...

  5. java单例模式(两种常用模式)

    单例模式是java中常见的设计模式 特点: 单例类只能有一个实例 单例类必须自己创建自己的唯一实例 单例类必须给所有的其他对象提供这一实例 单例模式是某个类只能有一个实例而且自动实例化并且向整个系统提 ...

  6. java 单例模式的几种写法

    一.懒汉式 public class Singleton{ private static Singleton instance = null; private Singleton(){} public ...

  7. JAVA单例模式的几种写法

    /** * 单例模式懒汉式(双重检锁线程安全.JDK1.5之后) */ public class Singleton { private static volatile Singleton singl ...

  8. Java单例模式的5种实现方式

    1.饿汉式.不支持并发: package com.ou; //饿汉式 public class Singleton1 { private Singleton1() { } private static ...

  9. 用java单例模式实现面板切换

    1.首先介绍一下什么是单例模式: java单例模式是一种常见的设计模式,那么我们先看看懒汉模式: public class Singleton_ { //设为私有方法,防止被外部类引用或实例 priv ...

随机推荐

  1. LeetCode 1257. Smallest Common Region

    原题链接在这里:https://leetcode.com/problems/smallest-common-region/ 题目: You are given some lists of region ...

  2. n8n 试用

    前边有简单的介绍n8n,如果大家看了官方网站会有一个比较醒目的说明zapier以及tray.io的开源替代方案 以下是一个简单的试用 环境准备 docker-compose 文件   version: ...

  3. C++中二分法之upper_bound()、lower_bound、binary_search()函数

    前言 数组.容器vector都适用,在头文件"algorithm"中 下面的例子是针对容器的,注意返回的是距离元素3最近的指针it,输出的是*it结果为元素4,假如我想得到位置而非 ...

  4. [LeetCode] 63. Unique Paths II 不同的路径之二

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...

  5. Sentinel: 接入控制台实时查看监控数据

    Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理.监控(单机和集群),规则管理和推送的功能. 比如我们之前是直接在代码中初始限流的值,接入控制台后可以直接通过控制台进行限流 ...

  6. Codeforces Round #607 (Div. 1) Solution

    从这里开始 比赛目录 我又不太会 div 1 A? 我菜爆了... Problem A Cut and Paste 暴力模拟一下. Code #include <bits/stdc++.h> ...

  7. 推荐一款手机清理工具App悟空清理

    推荐一款手机清理工具App悟空清理 1 介绍 悟空清理是一款完全免费的手机加速与存储空间清理工具软件,强力去除顽固垃圾,使手机运行更畅快. 2 特色功能介绍 悟空在手,清理无忧!悟空清理,人人都在用的 ...

  8. sql server 批量备份数据库及删除N天前的备份数据

    很多时候,我们都需要将数据库进行备份,当服务器上数据库较多时,不可能一个数据库创建一个定时任务进行备份,这时,就需要进行批量的数据库备份操作,好了,废话不多说,具体实现语句如下: 1 2 3 4 5 ...

  9. Java中json使用与问题汇总

    一.JSON 解析类库 FastJson: 阿里巴巴开发的 JSON 库,性能十分优秀. 在maven项目的pom文件中以下依赖 <dependency> <groupId>c ...

  10. vue表单验证不通过,依然能执行点击事件里面的代码?

    遇到的问题:表单提交的时候,写了rules,明明验证不通过依然执行了点击事件里面的代码. 这个验证有什么用? 后来 我看elementUI组件才发现,我漏写了几行代码. methods里面这样写 完美 ...