PS:首先我们要先知道什么是单例,为什么要用单例,用的好处是什么等问题来看。

1:java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例、饿汉式单例

单例模式有以下特点:  

  1、单例类只能有一个实例。
  2、单例类必须自己创建自己的唯一实例。
  3、单例类必须给所有其他对象提供这一实例。

目的

  单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

2:懒汉式

先把单例类写出来

public class SingletonTest {
//懒汉式单例类.在第一次调用的时候实例化自己
private SingletonTest() {}
private static SingletonTest single=null;
//静态工厂方法
public static SingletonTest getInstance() {
if (single == null) {
single = new SingletonTest();
System.out.println("创建一次");
}
return single;
} public void show(){
System.out.println("我是show");
} }

这里直接上代码,代码中有详解

public class SingletonTest2 {

    public static void main(String[] args) {
// TODO Auto-generated method stub
//故意写获取两次,创建两个对象
SingletonTest singleton=SingletonTest.getInstance();
SingletonTest singleton2=SingletonTest.getInstance(); //Singleton对象只创建一次,但是写两次还是可以的,而且方法都是可以调用的,但是看下面
singleton.show();
singleton2.show(); //两个对象的表现形式一样
if(singleton == singleton2){
System.out.println("该对象的字符串表示形式:");
System.out.println("singleton :"+singleton.toString());
System.out.println("singleton2:"+singleton2.toString());
}
}

由上面的图可以看出就算多创建几个对象,在底部也是只有一个singleton对象实例,而且创建出来的对象的字符串表现形式也是一样的,有的人肯定有疑问,那平常两个对象是什么样子的呢,我下面给你解释说明,在这之前我写说一下这个懒汉式需要注意的地方,它是线程不安全的,并发环境下很可能出现多个Singleton实例,有很多方法可以解决,比如说同步锁,静态内部类等,这里主要说静态内部类,这个比较好点,

public class Singleton3 {
private static class SingletonHolder {
private static final Singleton3 INSTANCE = new Singleton3();
}
private Singleton3 (){}
public static final Singleton3 getInstance() {
System.out.println("singleton创建");
return SingletonHolder.INSTANCE;
}
}

调用:

Singleton3 singleton3=Singleton3.getInstance();
Singleton3 singleton4=Singleton3.getInstance();
if(singleton3 == singleton4){
System.out.println("该对象的字符串表示形式:");
System.out.println("singleton3:"+singleton3.toString());
System.out.println("singleton4:"+singleton4.toString());
}

结果图:

这里我也是创建了两个对象来说明,神奇的是打印了两次singleton创建,这难道是又创建成功了的对象吗?答案是:虽然打印了两次,对象名也有两个,但是该对象的字符串表示形式还是一样的,而且大家都知道static的用法,就是在类被加载的同时该singleton对象就已经被创建,后期不会再被创建,就算后期自己又调用了getInstance()方法,但底层还是公用的一个Singleton对象.

同样,我写了一个普通的类,来同时创建两个对象,并且打印他们的toString()方法,如下:

     QuBie qb1=new QuBie();
QuBie qb2=new QuBie();
if(qb1 == qb2){
System.out.println("该对象的字符串表示形式:");
System.out.println("singleton3:"+qb1.toString());
System.out.println("singleton4:"+qb2.toString());
}else{
System.out.println("该对象的字符串表示形式:");
System.out.println("singleton3:"+qb1.toString());
System.out.println("singleton4:"+qb2.toString());
}

由此可看出来对象的字符串表示形式是不一样的

3:饿汉式单例

饿汉式单例类.在类初始化时,已经自行实例化

public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}

因为这本身就是static修饰的方法,所以是在类加载的时候被创建,后期不会再改变,所以线程是安全的。

4:双检锁/双重校验锁

描述:采用双锁机制,安全且在多线程情况下能保持高性能。多线程安全

 

public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

这里的两次判断,第一判断:效率,第二判断:避免同步。之所以这样是因为避免加锁后,再次加锁。大大增强了执行效率。

(适配器、单例、静态代理、简单工厂设计模式)https://www.cnblogs.com/cmusketeer/p/8146510.html

Java-单例模式详解(图文并茂,简单易懂)的更多相关文章

  1. 9种Java单例模式详解(推荐)

    单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象.  懒汉式(线程不安全) 其主要表现在单例类在外 ...

  2. Java 单例模式详解

    概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. ...

  3. 【JAVA单例模式详解】

    设计模式是一种思想,适合于任何一门面向对象的语言.共有23种设计模式. 单例设计模式所解决的问题就是:保证类的对象在内存中唯一. 举例: A.B类都想要操作配置文件信息Config.java,所以在方 ...

  4. Java 单例模式详解(转)

    概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己自己创建自己的唯一实例. ...

  5. 9种Java单例模式详解

    单例模式的特点 一个类只允许产生一个实例化对象. 单例类构造方法私有化,不允许外部创建对象. 单例类向外提供静态方法,调用方法返回内部创建的实例化对象. 懒汉式(线程不安全) 其主要表现在单例类在外部 ...

  6. java单例模式详解

    饿汉法 饿汉法就是在第一次引用该类的时候就创建对象实例,而不管实际是否需要创建.代码如下: public class Singleton { private static Singleton = ne ...

  7. Java集合详解6:TreeMap和红黑树

    Java集合详解6:TreeMap和红黑树 初识TreeMap 之前的文章讲解了两种Map,分别是HashMap与LinkedHashMap,它们保证了以O(1)的时间复杂度进行增.删.改.查,从存储 ...

  8. Java虚拟机详解----JVM常见问题总结

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  9. Java面向对象详解

    Java面向对象详解 前言:接触项目开发也有很长一段时间了,最近开始萌发出想回过头来写写以前学 过的基础知识的想法.一是原来刚开始学习接触编程,一个人跌跌撞撞摸索着往前走,初学的时候很多东西理解的也懵 ...

  10. Java synchronized 详解

    Java synchronized 详解 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 1.当两个并发线程访问同一个对象object ...

随机推荐

  1. thinkphp系列:类的自动加载是如何设计的

    在使用框架开发时,可以发现框架有很多核心类,却很少看到显示的引入某个文件的代码,这是因为框架都采用了类的自动加载机制,即使用到类时,框架会自动找到该类所在文件的位置并引入该文件.为了更容易看出代码思路 ...

  2. Service使用详解

    Service是Android系统中的四大组件之一,主要有两个应用场景:后台运行和跨进程访问.Service可以在后台执行长时间运行操作而不提供用户界面,除非系统必须回收内存资源,否则系统不会停止或销 ...

  3. 深入理解ES6之——JS类的相关知识

    基本的类声明 类声明以class关键字开始,其后是类的名称:剩余部分的语法看起来像对象字面量中的方法简写,并且在方法之间不需要使用逗号. class Person { //等价于prototype的构 ...

  4. Thinkphp导入外部类的方法

    相信很多人在使用TP时候都苦恼使用外部类各种不成功 下面为大家详细介绍下引用方法和注意细节 手动加载第三方类库 由于第三发类库没有具体的命名空间,所以需要使用以下几种方法手动导入 1.import方法 ...

  5. iOS 图片本地存储、本地获取、本地删除

    在iOS开发中.经常用到图片的本地化. iOS 图片本地存储.本地获取.本地删除,可以通过以下类方法实现. p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: ...

  6. CCF-201312-4-有趣的数

    问题描述 试题编号: 201312-4 试题名称: 有趣的数 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, ...

  7. python学习之路day1

    学习总结: 变量,字符的由来,python2和python3的区别,控制语句:if,for,while,break,continue用法 学习示例: if用法1:判断年龄 # -*- coding: ...

  8. iOS中常见的锁

    多线程的安全隐患 一块资源可能会被多个线程共享,也就是说多个线程可能会访问同一块资源. 比如多个线程同时操作同一个对象,同一个变量. 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题. 比 ...

  9. mongoDB之数据类型

    mongoDB之数据类型 Object  ID :文档的id String: 字符串,最常用,必须是utf-8 Boolean:布尔值,true 或者false Integer:整数 Double:浮 ...

  10. PHP运算符优先级 运算符分类

    运算符 运算符是可以通过给出的一或多个值(用编程行话来说,表达式)来产生另一个值(因而整个结构成为一个表达式)的东西. 运算符可按照其能接受几个值来分组.一元运算符只能接受一个值,例如 !(逻辑取反运 ...