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

多线程中的单例模式

  这里面通过代码来体会一下在多线程中如何正确的编写单例模式的代码。相同的代码如下,不同的是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. CI框架 -- 在视图文件中使用 PHP 替代语法

    如果你不使用 CodeIgniter 的 模板引擎, 那么你就只能在视图文件中使用纯 PHP 语法了.为了精简视图文件, 使其更可读,建议你在写控制结构或 echo 语句时使用 PHP 的替代语法. ...

  2. 使用Camera功能 AREA的理解

    转至 http://blog.csdn.net/think_soft/article/details/7998478 使用Camera功能 大多数的Camera功能都是使用Camera.Paramet ...

  3. JQuery $.each遍历JSON字符串报Uncaught TypeError:Cannot use 'in' operator to search for

    查看一个简单的jQuery的例子来遍历一个JavaScript数组对象. [js] view plaincopy   var json = [ {"id":"1" ...

  4. iOS:App 内部更改使用语言/ 重定义系统的宏

    代码部分 #undef NSLocalizedString #define NSLocalizedString(key, comment) \ NSLocalizedStringFromTable(k ...

  5. 清除 Xcode 项目缓存

    运行错误.编译错误.发布错误可尝试清除 Xcode 缓存:清除 Xcode 缓存也能减少占用磁盘空间. (1)前往文件夹(control+shift+G),删除里面的文件: /Users/用户名/Li ...

  6. Node.js静态文件服务器实战[转]

    p.s. 在下面这篇文章的指导下,做了一个静态文件服务器,见:https://github.com/walkerwzy/node_static_server ==== 这是一篇阐述得比较详细的文章,从 ...

  7. windows mongodb最常用命令简单归纳

    在windows安装好了windows,首先记得要把mongodb bin目录路径放在 系统环境变量的path中,确定之后即配置好了mongo的环境变量,在dos命令框中输入mongo会出现如下 版本 ...

  8. 详解BarTender选项大小调整模式

    BarTender大小调整模式是DotCode码制独有的符号体系特殊选项.DotCode 符号可能在形状上有所不同,包括从接近正方形的点阵到细长的色带,而“大小调整模式”选项通过指定点阵的配置来确定 ...

  9. linux 安装lnmp

    wget -c http://soft.vpser.net/lnmp/lnmp1.4.tar.gz && tar zxf lnmp1.4.tar.gz && cd ln ...

  10. NPOI把Excel导入到数据库

    二,把Excel中的数据导入到数据库的具体步骤: protected void Button1_Click(object sender, EventArgs e)        {           ...