转发自:http://blog.csdn.net/ligang7560/article/details/50890282

单例模式的多种实现方式

我们都知道单例模式有几种常用的写法:

- 饿汉模式

- 懒汉模式

- 双重校验锁

- 静态内部类

- 静态代码块

我们来看一下这几种模式在多线程的场景中,能否保持单例

1.饿汉模式

public class HungrySingleton {

    //立即加载模式
private static HungrySingleton hungrySingleton = new HungrySingleton(); private HungrySingleton(){} public static HungrySingleton getInstance(){
return hungrySingleton;
} }

接下来我们写一个线程类,再写一个测试类,来看下饿汉模式在多线程下的表现如何:

运行测试类结果如下:

	546862187
546862187
546862187

这说明饿汉模式是线程安全,在多线程的情况下,也能够保持单例.

2.懒汉模式

public class LazySingleton {

    private static LazySingleton lazySingleton;

    private LazySingleton() {}

    public static LazySingleton getInstance(){
if(lazySingleton!=null){
}else{
lazySingleton = new LazySingleton();
}
return lazySingleton;
} }

同样的我们来写一个线程类,写一个测试类;



运行结果:

	2030251396
546862187
2030251396

我们看到对象返回的哈希值不一致了,这就说明他们已经不是同一个对象实例了,也就是说这种写法是线程不安全的,那么我们对它进行如下的改造:

public class LazySingleton {

    private static LazySingleton lazySingleton;

    private LazySingleton() {}

    //整个方法加同步,效率低
synchronized public static LazySingleton getInstance(){
if(lazySingleton!=null){
}else{
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}

我们给整个getInstance方法添加了个synchronized关键字,才保证多线程的情况下也能保持单例,我们再运行一下测试类:

1638084561
1638084561
1638084561

这时我们看见已经没有问题了,就是说写法是正确的,但是这种写法导致所以并发的线程获取实例时都是排队进行的,那么就会导致性能低下,接下来我们尝试另外一种写法,就是我们的第三种写法:双重校验锁.

3. 双重校验锁

public class LazySingleton {

    private static LazySingleton lazySingleton;

    private LazySingleton() {}

     public static LazySingleton getInstance(){
if(lazySingleton!=null){
}else{
synchronized (LazySingleton.class){
if(lazySingleton==null){
lazySingleton = new LazySingleton();
}
} }
return lazySingleton;
}
}

我们将排队进行的范围进行缩小,同时采用校验两次为空的方法,来保证单例模式的正确性,接下来我们来看一下测试结果:

2030251396
2030251396
2030251396

OK,没有问题.

4.静态内部类

public class StaticInnerClassSingleton {
//通过写一个静态的内部类来创建实例
private static class SingletonHandle{
private static StaticInnerClassSingleton singleton = new StaticInnerClassSingleton();
} private StaticInnerClassSingleton(){} public static StaticInnerClassSingleton getInstance(){
return SingletonHandle.singleton;
} }

测试类和上面的都差不多,我就不贴图片了,直接看测试结果:

1523917841
1523917841
1523917841

没有问题,这种方式也是线程安全的,接下来我们看最后一种方式

5.静态代码块

public class StaticSingleton {

    private static StaticSingleton staticSingleton=null;

    private StaticSingleton(){};

    static {
//通过静态代码块的执行,来获取实例
staticSingleton = new StaticSingleton();
} public static StaticSingleton getInstance(){
return staticSingleton;
}
}

不废话了,直接看测试结果:

2030251396
2030251396
2030251396

没有问题,那么以上我们就介绍了5中关于多线程中单例模式的写法,其中呢就懒汉模式的一般写法容易造成错误,其他的写法都是线程安全的,文章中的代码我已经上传到github了,有需要的同学可以下载下来自己试试.

https://github.com/JokerLigang/Singleton.git

java多线程与单例模式(Singleton)不得不说的故事的更多相关文章

  1. java设计模式之 单例模式 Singleton

    static 的应用 单例模式 Singleton 单例:保证一个类在系统中最多只创建一个实例. 好处:由于过多创建对象实例,会产生过多的系统垃圾,需要GC频繁回收,由于GC会占用较大的系统资源,所有 ...

  2. Java 设计模式(三)-单例模式(Singleton Pattern)

    1     概念定义 1.1   定义 确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 1.2   类型 创建类模式 1.3   难点 1)多个虚拟机 当系统中的单例类被拷贝运行在多 ...

  3. java多线程环境单例模式实现详解

    Abstract 在开发中,如果某个实例的创建需要消耗很多系统资源,那么我们通常会使用惰性加载机制,也就是说只有当使用到这个实例的时候才会创建这个实例,这个好处在单例模式中得到了广泛应用.这个机制在s ...

  4. Java设计模式之单例模式 - Singleton

    用来创建独一无二的,是能有一个实例的对象的入场券.告诉你一个好消息,单例模式的类图可以说是所有模式的类图中最简单的,事实上,它的类图上只有一个类!但是,可不要兴奋过头,尽管从类设计的视角来说很简单,但 ...

  5. Java 基础:单例模式 Singleton Pattern

    1.简介 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...

  6. java 多线程,单例模式类(创建对象)最优写法

    单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ...

  7. Java多线程之单例模式(线程安全)

    package org.study2.javabase.ThreadsDemo.sync; /** * @Auther:GongXingRui * @Date:2018/9/20 * @Descrip ...

  8. Java多线程核心技术(五)单例模式与多线程

    本文只需要考虑一件事:如何使单例模式遇到多线程是安全的.正确的 1.立即加载 / "饿汉模式" 什么是立即加载?立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接 ...

  9. 创建模式--单例模式Singleton(JAVA)

    创建模式之单例模式        在面试时经常会有人问单例模式,单例模式是在整个系统运行中仅且仅有一个实例,在被调用.我们熟知的Calendar就是这种,        Calendar.newIns ...

随机推荐

  1. c#通过oledb获取excel文件表结构信息

    这个问题来自论坛提问,同理可以获得access等数据库的表结构信息. using System; namespace ConsoleApplication11 { class Program { pu ...

  2. 第 27 章 CSS 传统布局[下]

    学习要点: 1.定位布局 2.box-sizing 3.resize 主讲教师:李炎恢 本章主要探讨 HTML5 中 CSS 早期所使用的传统布局,很多情况下,这些布局方式还是非常有用的. 一.定位布 ...

  3. java 数据库连接池

    1. About java利用jdbc直接连接数据库,经常取得连接,用完释放,很浪费系统资源 2. Code Java代码 package com.cdv.mam.db; import java.sq ...

  4. .NET删除字节数组中的0字节

    private static byte[] Decode(byte[] packet) { ; while (packet[i] == 0) { --i; } ]; Array.Copy(packet ...

  5. rabbitmq qos prefetch count的设置与作用

    因为原来使用了MQ作为rpc机制,随着客户交易量越来越大,很多服务器推送行情的压力很大,最近打算重写为批量模式,又重新看了下qos和prefetch设置的作用以确定优化的具体细节. 消费者在开启ack ...

  6. angular学习的一些小笔记(中)之directive

    directive里面的几个配置,上代码就清晰了 <!DOCTYPE html> <html ng-app='app'> <head> <meta chars ...

  7. html和css的编码规范

    HTML和CSS编码规范内容 一.HTML规范 二.CSS规范 三.注意事项: 四.常用的命名规则 五.CSS样式表文件命名 六.文件命名规则 一.HTML规范: 1.代码规范 页面的第一行添加标准模 ...

  8. C#实现jQuery的方法连缀

    jQuery的方法连缀使用起来非常方便,可以简化语句,让代码变得清晰简洁.那C#的类方法能不能也实现类似的功能呢?基于这样的疑惑,研究了一下jQuery的源代码,发现就是需要方法连缀的函数方法最后返回 ...

  9. Python的下载与安装

    linux系统由于自身的需要,自带了Python,而Windows的系统就没有自带Python.本篇Blog介绍在win8.1下,安装Pathon需要注意的问题,包括常见的0x80240017.250 ...

  10. [deviceone开发]-do_Socket组件示例

    一.简介 do_Socket只实现了socket的客户端的功能,这个示例完整了展示了组件的基本用法,需要和sockettest3工具配合使用,sockettest3做为一个socket server来 ...