这里我们介绍一下在多线程中如何安全正确的编写单例模式的代码。不知为何,恰如其分的话总是姗姗来迟,错过最恰当的时机。

多线程中的单例模式

  这里面通过代码来体会一下在多线程中如何正确的编写单例模式的代码。相同的代码如下,不同的是Object这个类。

package com.linux.huhx.thread3.singleDesign_1;

/**
* @Author: huhx
* @Date: 2017-10-31 下午 4:28
*/
public class SingleDesignTest1 {
public static void main(String[] args) {
MyThread[] threads = new MyThread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new MyThread();
}
for (int i = 0; i < 10; i++) {
threads[i].start();
}
} static class MyThread extends Thread {
@Override
public void run() {
System.out.println(MyObject*.getInstance().hashCode());
}
}
}

以下的不同测试类的结果,都是基于修改MyThread里面run方法的MyObject*的值。

一、立即加载方式(饿汉模式)

public class MyObject1 {
private static MyObject1 myObject = new MyObject1();
private MyObject1() {} public static MyObject1 getInstance() {
return myObject;
}
}

安全:一次的打印结果如下


二、延迟加载方式(懒汉模式)

public class MyObject2 {
private static MyObject2 myObject;
private MyObject2() {} public static MyObject2 getInstance() {
try {
if (myObject == null) {
// 模拟一些准备的耗时操作
TimeUnit.SECONDS.sleep(2);
myObject = new MyObject2();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

不正确:一次的打印结果


三、延迟加载解决方案之声明synchronized

public class MyObject3 {
private static MyObject3 myObject;
private MyObject3() {} public synchronized static MyObject3 getInstance() {
try {
if (myObject == null) {
// 模拟一些准备的耗时操作
TimeUnit.SECONDS.sleep(2);
myObject = new MyObject3();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

安全:一次的打印结果


效率比较低下:同步运行,下一个线程想要取得对象,则必须等待上一个线程释放锁之后,才可以继续执行。

四、延迟加载解决方案之同步代码块

public class MyObject4 {
private static MyObject4 myObject;
private MyObject4() {} public static MyObject4 getInstance() {
try {
synchronized (MyObject4.class) {
if (myObject == null) {
// 模拟一些准备的耗时操作
TimeUnit.SECONDS.sleep(2);
myObject = new MyObject4();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

安全:一次的打印结果如下


效率比较低下:和上述的synchronized同步方法一样都是同步运行的。

五、延迟加载解决方案之同步部分代码块

public class MyObject5 {
private static MyObject5 myObject;
private MyObject5() {} public static MyObject5 getInstance() {
try {
if (myObject == null) {
// 模拟一些准备的耗时操作
TimeUnit.SECONDS.sleep(2);
synchronized (MyObject5.class) {
myObject = new MyObject5();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

不安全:一次的打印结果如下


六、延迟加载解决方案之DCL双检查锁机制

public class MyObject6 {
private volatile static MyObject6 myObject;
private MyObject6() {} public static MyObject6 getInstance() {
try {
if (myObject == null) {
// 模拟一些准备的耗时操作
TimeUnit.SECONDS.sleep(2);
synchronized (MyObject6.class) {
if (myObject == null) {
myObject = new MyObject6();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return myObject;
}
}

安全:一次的打印结果如下


使用双重检查锁功能,成功地解决了“懒汉模式”遇到多线程的问题。DCL也是大多数多线程结合单例模式使用的解决方案。

七、使用静态内置类实现单例模式

public class MyObject7 {
private static class MyObjectHandler {
private static MyObject7 myObject = new MyObject7();
} private MyObject7() {} public static MyObject7 getInstance() {
return MyObjectHandler.myObject;
}
}

安全:一次的打印结果如下


八、使用static代码块实现单例模式

public class MyObject8 {
private static MyObject8 myObject = null; static {
myObject = new MyObject8();
} private MyObject8() {} public static MyObject8 getInstance() {
return myObject;
}
}

安全:一次的打印结果如下


友情链接

java高级---->Thread之单例模式的使用的更多相关文章

  1. java高级---->Thread之ScheduledExecutorService的使用

    ScheduledExecutorService的主要作用就是可以将定时任务与线程池功能结合使用.今天我们来学习一下ScheduledExecutorService的用法.我们都太渺小了,那么容易便湮 ...

  2. java高级---->Thread之ExecutorService的使用

    今天我们通过实例来学习一下ExecutorService的用法.我徒然学会了抗拒热闹,却还来不及透悟真正的冷清. ExecutorService的简单实例 一.ExecutorService的简单使用 ...

  3. java高级---->Thread之Phaser的使用

    Phaser提供了动态增parties计数,这点比CyclicBarrier类操作parties更加方便.它是jdk1.7新增的类,今天我们就来学习一下它的用法.尘埃落定之后,回忆别来挑拨. Phas ...

  4. java高级---->Thread之CompletionService的使用

    CompletionService的功能是以异步的方式一边生产新的任务,一边处理已完成任务的结果,这样可以将执行任务与处理任务分离开来进行处理.今天我们通过实例来学习一下CompletionServi ...

  5. java高级---->Thread之CyclicBarrier的使用

    CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).今天我们就学习一下CyclicBarrier的用法. Cycl ...

  6. java高级---->Thread之BlockingQueue的使用

    今天我们通过实例来学习一下BlockingQueue的用法.梦想,可以天花乱坠,理想,是我们一步一个脚印踩出来的坎坷道路. BlockingQueue的实例 官方文档上的对于BlockingQueue ...

  7. java高级---->Thread之Exchanger的使用

    Exchanger可以在两个线程之间交换数据,只能是2个线程,他不支持更多的线程之间互换数据.今天我们就通过实例来学习一下Exchanger的用法. Exchanger的简单实例 Exchanger是 ...

  8. java高级---->Thread之FutureTask的使用

    FutureTask类是Future 的一个实现,并实现了Runnable,所以可通过Excutor(线程池) 来执行,也可传递给Thread对象执行.今天我们通过实例来学习一下FutureTask的 ...

  9. java高级---->Thread之Condition的使用

    Condition 将 Object 监视器方法(wait.notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set ...

随机推荐

  1. asp InStr

    <script type="text/vbscript"> txt="This is a beautiful day!"document.write ...

  2. 用Visual C#创建Windows服务程序

    一.Windows服务介绍: Windows服务以前被称作NT服务,是一些运行在Windows NT.Windows 2000和Windows XP等操作系统下用户环境以外的程序.在以前,编写Wind ...

  3. CI框架 -- 创建类库

    当我们使用 “类库” 这个词的时候,通常我们指的是位于 libraries 这个目录下的那些类. 接下来我们将介绍 如何在 application/libraries 目录下创建你自己的类库,和全局的 ...

  4. nodejs基础 -- 多进程

    Node.js 多进程 我们都知道 Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的系统上创建多个子进程,从而提高性能. 每个子进程总是带有三个 ...

  5. List转DataTable(反射) ; 将泛型集合类转换成DataTable ; 将集合类转换成DataTable

    public class ConvertX { #region 将集合类转换成DataTable /// <summary> /// 将集合类转换成DataTable /// </s ...

  6. Python 判断文件是否存在的三种方法

    通常在读写文件之前,需要判断文件或目录是否存在,不然某些处理方法可能会使程序出错.所以最好在做任何操作之前,先判断文件是否存在. 这里将介绍三种判断文件或文件夹是否存在的方法,分别使用os模块.Try ...

  7. Linux下的rename命令

    Dos/Windows下,对文件改名用rename.而书上说,Linux下对文件或目录改名该用mv.我一直也是这样做的,却忽略了Linux下也有个叫rename的命令.都是rename,但功能上就有点 ...

  8. 新建maven指定jdk版本-eclipse新建maven项目报错The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path的解决方案

    具体表现为: 使用Eclipse+Maven建立了一个Javaweb工程,JSP页面顶端出现“红色”的报错信息:The superclass "javax.servlet.http.Http ...

  9. java中*和**的作用

    “*”就表示了所有的文件,但是“*”并不包括子目录下的文件: “**”匹配包含任意级子目录中所有的文件

  10. 通过MyEclipse部署web应用程序开发环境

    1.下载并安装MyEclipse10 2.配置java开发的jar包 3.配置tomcat服务器 4.部署tomcat服务器 点击Bronse可以查看部署后的文件夹目录 5.启动tomcat服务器 6 ...