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

多线程中的单例模式

  这里面通过代码来体会一下在多线程中如何正确的编写单例模式的代码。相同的代码如下,不同的是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. LintCode #3 统计数字

    解题思路请参考 代码(可以通过,不过很乱,需要整理): /// <summary> /// 计算n在数组[targetNum]中出现的次数 /// 形如:[0, 1, 2, 3, 4, 5 ...

  2. Keystone-manage 命令

    本文介绍Icehouse发行版的keystone-manage命令 keystone-manage是用来同keystone服务进行交互的命令行工具,通常该命令只用于不能通过HTTP API完成的操作, ...

  3. Fedora26 tftp-server设置

    安装tftp-server yum install -y  tftp-server 启动软件 systemctl start tftp.socket systemctl enable tftp.soc ...

  4. vim介绍/vim颜色显示和移动光标/ vim一般模式下移动光标/ vim一般模式下复制、剪切和粘贴

    5.1 vim介绍 5.2 vim颜色显示和移动光标 5.3 vim一般模式下移动光标 5.4 vim一般模式下复制.剪切和粘贴 vim   是vi的升级版本 vim 带有颜色显示 安装vim : y ...

  5. asp.net操作cookie类,包含datatable批量存入cookie

    以下是类: public class CookieMgr { #region 快速储存Cookie /// <summary> /// 快速储存Cookie /// </summar ...

  6. Linux服务器svn与项目同步

    命令:svn checkout svn://192.168.67.131/trunk/w1

  7. Run ASP.NET MVC site on mac (mono/xamarin studio)

    我们选择用xamarin studio来测试,如果你直接进xamarin的官网,那么会有一个更好看的网站和更复杂的流程(比如需要注册),我们直接到mono项目找mac的支持吧,点此进入 相关sdk和a ...

  8. input checkbox复选框点击获取当前选中状态jquery

    function checkAll(id) { //用is判断 // let checkStatus=$(id).is(':checked'); // console.log(checkStatus) ...

  9. mybatis-generator 的坑我都走了一遍

    一.简介 mybatis-geneator是一款mybatis自动代码生成工具,可以通过配置,快速生成mapper和xml文件. 二.配置方法 在项目的pom文件中添加插件配置 <plugin& ...

  10. geoserver PostGIS的安装和使用

    PostGIS是一个非常流行并且开源的具有空间分析能力的关系型数据库,它作为PostgreSQL数据库的一个插件.PostgreSQL是一个功能非常强大并且开源的关系型数据库.目前项目使用的版本为Po ...