2019独角兽企业重金招聘Python工程师标准>>>

1、说明:单例模式是最简单的设计模式之一,单例模式适合于一个类只有一个实例的情况。

2、要求:确保一个类只有一个实例被建立,并提供了一个对对象的全局访问指针 。

3、注意事项:如何正确构建线程安全的单例模式。

不正确的构建,示例代码加测试代码如下:

package org.com.jsoup;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPublicTest {public static   ThreadPublicTest test   ;private final String threadName;private ThreadPublicTest() {System.out.println("构建方法执行,当前执行线程名称为:" + Thread.currentThread().getName());
threadName = Thread.currentThread().getName();}public String getThreadName() {return threadName;}public static   ThreadPublicTest getThreadPublicTest() {if (test == null){test = new ThreadPublicTest();}return test;}/*** @param args测试代码* @throws InterruptedException */public static void main(String[] args) throws InterruptedException {// 开始时间long beginTime = System.nanoTime();final int theadMax = 10;final CyclicBarrier cyclicBarrier = new CyclicBarrier(theadMax);// 创建一个线程池,限制为最多theadMax个线程final ExecutorService exec = Executors.newFixedThreadPool(theadMax);// 创建锁存器,设置为theadMax个,表示要等待theadMax个线程执行完final CountDownLatch downLatch = new CountDownLatch(theadMax);for (int i = 0; i < theadMax; i++) {Runnable runable = new Runnable() {@Overridepublic void run() {try {// 排队等待cyclicBarrier.await();ThreadPublicTest test = ThreadPublicTest.getThreadPublicTest();System.out.println(String.format("对象名称:%s 线程名称:%s",test.getThreadName(),Thread.currentThread().getName()));} catch (Exception e) {// 处理异常} finally {// 减少计数值downLatch.countDown();}}};// 将任务放入线程池执行exec.execute(runable);}downLatch.await();// 等待所有的并发访问完exec.shutdown();// 关闭线程池System.out.println("执行完毕:" + (System.nanoTime() - beginTime));}}

上面的测试代码输出为:

构建方法执行,当前执行线程名称为:pool-1-thread-1

构建方法执行,当前执行线程名称为:pool-1-thread-10

对象名称:pool-1-thread-10 线程名称:pool-1-thread-4

对象名称:pool-1-thread-10 线程名称:pool-1-thread-10

对象名称:pool-1-thread-10 线程名称:pool-1-thread-2

对象名称:pool-1-thread-10 线程名称:pool-1-thread-8

对象名称:pool-1-thread-10 线程名称:pool-1-thread-6

对象名称:pool-1-thread-1 线程名称:pool-1-thread-1

对象名称:pool-1-thread-10 线程名称:pool-1-thread-5

对象名称:pool-1-thread-10 线程名称:pool-1-thread-3

对象名称:pool-1-thread-10 线程名称:pool-1-thread-7

对象名称:pool-1-thread-10 线程名称:pool-1-thread-9

执行完毕:57840462

说明这个对象的构造方法执行了多次,于是这不是线程安全的。
线程安全的构造方式1,示例代码加测试代码如下:
package org.com.jsoup;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPublicTest {public static  final ThreadPublicTest test  = new ThreadPublicTest() ;private final String threadName;private ThreadPublicTest() {System.out.println("构建方法执行,当前执行线程名称为:" +  Thread.currentThread().getName());threadName = Thread.currentThread().getName();}public String getThreadName() {return threadName;}public static   ThreadPublicTest getThreadPublicTest() {return test;}/*** @param args* @throws InterruptedException */public static void main(String[] args) throws InterruptedException {// 开始时间long beginTime = System.nanoTime();final int theadMax = 10;final CyclicBarrier cyclicBarrier = new CyclicBarrier(theadMax);// 创建一个线程池,限制为最多theadMax个线程final ExecutorService exec = Executors.newFixedThreadPool(theadMax);// 创建锁存器,设置为theadMax个,表示要等待theadMax个线程执行完final CountDownLatch downLatch = new CountDownLatch(theadMax);for (int i = 0; i < theadMax; i++) {Runnable runable = new Runnable() {@Overridepublic void run() {try {// 排队等待cyclicBarrier.await();ThreadPublicTest test = ThreadPublicTest.getThreadPublicTest();System.out.println(String.format("对象名称:%s 线程名称:%s",test.getThreadName(),Thread.currentThread().getName()));} catch (Exception e) {// 处理异常} finally {// 减少计数值downLatch.countDown();}}};// 将任务放入线程池执行exec.execute(runable);}downLatch.await();// 等待所有的并发访问完exec.shutdown();// 关闭线程池System.out.println("执行完毕:" + (System.nanoTime() - beginTime));}}

看看执行结果:

构建方法执行,当前执行线程名称为:main
对象名称:main 线程名称:pool-1-thread-1
对象名称:main 线程名称:pool-1-thread-6
对象名称:main 线程名称:pool-1-thread-2
对象名称:main 线程名称:pool-1-thread-4
对象名称:main 线程名称:pool-1-thread-8
对象名称:main 线程名称:pool-1-thread-10
对象名称:main 线程名称:pool-1-thread-3
对象名称:main 线程名称:pool-1-thread-5
对象名称:main 线程名称:pool-1-thread-7
对象名称:main 线程名称:pool-1-thread-9

执行完毕:51450575

可以看到构建方法只执行了一次,这种实现方法的好处是代码简洁,线程获取单例的方法执行效率高,缺点就是代码一加载就会执行对象初始化,所以上面我们看到构造方法是在主线程中执行的。

那么我们采用线程同步的方式来实现延迟初始化,以下是示例加测试代码:

package org.com.jsoup;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPublicTest {public static   ThreadPublicTest test  ;private final String threadName;private ThreadPublicTest() {System.out.println("构建方法执行,当前执行线程名称为:" +  Thread.currentThread().getName());threadName = Thread.currentThread().getName();}public String getThreadName() {return threadName;}public static  synchronized ThreadPublicTest getThreadPublicTest() {if (test == null){test    = new ThreadPublicTest() ;}return test;}/*** @param args* @throws InterruptedException */public static void main(String[] args) throws InterruptedException {// 开始时间long beginTime = System.nanoTime();final int theadMax = 10;final CyclicBarrier cyclicBarrier = new CyclicBarrier(theadMax);// 创建一个线程池,限制为最多theadMax个线程final ExecutorService exec = Executors.newFixedThreadPool(theadMax);// 创建锁存器,设置为theadMax个,表示要等待theadMax个线程执行完final CountDownLatch downLatch = new CountDownLatch(theadMax);for (int i = 0; i < theadMax; i++) {Runnable runable = new Runnable() {@Overridepublic void run() {try {// 排队等待cyclicBarrier.await();ThreadPublicTest test = ThreadPublicTest.getThreadPublicTest();System.out.println(String.format("对象名称:%s 线程名称:%s",test.getThreadName(),Thread.currentThread().getName()));} catch (Exception e) {// 处理异常} finally {// 减少计数值downLatch.countDown();}}};// 将任务放入线程池执行exec.execute(runable);}downLatch.await();// 等待所有的并发访问完exec.shutdown();// 关闭线程池System.out.println("执行完毕:" + (System.nanoTime() - beginTime));}}

看看测试的执行结果:

构建方法执行,当前执行线程名称为:pool-1-thread-10

对象名称:pool-1-thread-10 线程名称:pool-1-thread-5

对象名称:pool-1-thread-10 线程名称:pool-1-thread-1

对象名称:pool-1-thread-10 线程名称:pool-1-thread-10

对象名称:pool-1-thread-10 线程名称:pool-1-thread-4

对象名称:pool-1-thread-10 线程名称:pool-1-thread-7

对象名称:pool-1-thread-10 线程名称:pool-1-thread-6

对象名称:pool-1-thread-10 线程名称:pool-1-thread-3

对象名称:pool-1-thread-10 线程名称:pool-1-thread-8

对象名称:pool-1-thread-10 线程名称:pool-1-thread-9

对象名称:pool-1-thread-10 线程名称:pool-1-thread-2

执行完毕:44952622

上面的执行结果表明单例对象是在子线程中执行的,好处就是,系统要用到单例对象时才构造,避免不使用也进行构造而浪费内存,缺点就是线程获取这个单例对象时每次都要判断并加了synchronized进行线程同步,执行效率稍低。
还有更好的方法吗?或许下面的示例可以(延长初始化点位类模式):
package org.com.jsoup;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPublicTest {private static class InternalHalder{//JVM会根据需要的时候才会初始化ThreadPublicTestpublic static final ThreadPublicTest test = new ThreadPublicTest();}public static   ThreadPublicTest test  ;private final String threadName;private ThreadPublicTest() {System.out.println("构建方法执行,当前执行线程名称为:" +  Thread.currentThread().getName());threadName = Thread.currentThread().getName();}public String getThreadName() {return threadName;}public static  ThreadPublicTest getThreadPublicTest() {return InternalHalder.test;}/*** @param args* @throws InterruptedException */public static void main(String[] args) throws InterruptedException {// 开始时间long beginTime = System.nanoTime();final int theadMax = 10;final CyclicBarrier cyclicBarrier = new CyclicBarrier(theadMax);// 创建一个线程池,限制为最多theadMax个线程final ExecutorService exec = Executors.newFixedThreadPool(theadMax);// 创建锁存器,设置为theadMax个,表示要等待theadMax个线程执行完final CountDownLatch downLatch = new CountDownLatch(theadMax);for (int i = 0; i < theadMax; i++) {Runnable runable = new Runnable() {@Overridepublic void run() {try {// 排队等待cyclicBarrier.await();ThreadPublicTest test = ThreadPublicTest.getThreadPublicTest();System.out.println(String.format("对象名称:%s 线程名称:%s",test.getThreadName(),Thread.currentThread().getName()));} catch (Exception e) {// 处理异常} finally {// 减少计数值downLatch.countDown();}}};// 将任务放入线程池执行exec.execute(runable);}downLatch.await();// 等待所有的并发访问完exec.shutdown();// 关闭线程池System.out.println("执行完毕:" + (System.nanoTime() - beginTime));}}

执行结果跟上面一个示例是一样,但是不一样的是减少了同步开销,性能优于上一个。

转载于:https://my.oschina.net/20076678/blog/80585

单例模式的练习-如何正确构建相关推荐

  1. 前端学习(3312):redux的正确构建

  2. 设计模式心得1(工厂模式+单例模式+构建器模式+原型模式+适配器模式)

    设计模式分类 大致按照模式的应用目标分类,设计模式可以分为创建型模式.结构型模式和行为型模式. 创建型模式,是对对象创建过程的各种问题和解决方案的总结,包括各种工厂模式(Factory.Abstrac ...

  3. 如何正确实施人工智能

    https://www.toutiao.com/a6687407462464619021/ 人工智能(AI)在人们的日常工作和生活中日益普及,而且企业越来越依赖于人工智能来完成一系列任务,因此IT团队 ...

  4. Java提高篇——单例模式

    阅读目录 介绍 在我们日常的工作中经常需要在应用程序中保持一个唯一的实例,如:IO处理,数据库操作等,由于这些对象都要占用重要的系统资源,所以我们必须限制这些实例的创建或始终使用一个公用的实例,这就是 ...

  5. python kotlin_用Java和Python模仿Kotlin构建器

    python kotlin 介绍 Kotlin可能现在是我最喜欢的语言,可能它提供的最酷的功能之一是基于几个功能构建的类型安全的生成器(稍后解释). 我发现自己真的很想在其他两种主要语言(Java和P ...

  6. 用Java和Python模仿Kotlin构建器

    介绍 Kotlin可能现在是我最喜欢的语言,并且它可能提供的最酷的功能之一是基于几个功能构建的类型安全的生成器(稍后解释). 我发现自己真的很想在其他两种主要语言(Java和Python)中使用此功能 ...

  7. React SSR: 基于 express 自构建 SSR 服务端渲染

    React SSR: 基于 express 自构建 SSR 服务端渲染 文章目录 React SSR: 基于 express 自构建 SSR 服务端渲染 完整代码示例 前情提要 构建 CSR 项目 项 ...

  8. 为任意屏幕尺寸构建 Android 界面

    /   今日科技快讯   / 北京时间2022年1月17日,我国在太原卫星发射中心用长征二号丁运载火箭,成功将试验十三号卫星发射升空,卫星顺利进入预定轨道,发射任务获得圆满成功. /   前言   / ...

  9. 一文带你了解s2i的原理使用,快速构建镜像

    源到镜像(S2I)是一个独立工具,在创建构建器镜像时非常有用.S2I是OpenShift 3中用于构建应用程序的主要策略.以下特性可能是您感兴趣: 速度 -使用S2I,组装过程可以执行大量复杂的操作, ...

最新文章

  1. Python与用户的交互 ,格式化输出的三种方式
  2. 最全面的Linux指令大全
  3. 汇编语言典型例子详解_从架构到 RTOS 详解 DSP 和 MCU 的区别和联系
  4. MOSS 直接动态安装webPart到页面
  5. python中模块的概念_Python中模块的概念
  6. java返回fail_Java集合中的fail-fast(快速失败)机制详解
  7. 机器学习是如何改善企业生产力的?(内附机器智能版图)
  8. koa mysql 按钮级权限_Vue 指令实现按钮级别权限管理功能
  9. 探索 Word 2007 开发(四):上传图片
  10. 95-170-046-源码-Time-Flink时间系统系列之ProcessFunction使用分析
  11. 实用的项目管理网络计划软件-MS Project
  12. 阿里云导出的镜像raw转换成vmdk格式工具
  13. mb是做1还是0_新手爸妈看过来:0-1岁宝宝这样做早教,省钱省心又实用
  14. MWorks建模、仿真、分析优化平台
  15. MER:1.8万字带你系统了解宏组学实验与分析(高通量测序应用于病原体和害虫诊断——综述与实用性建议)...
  16. 数据项组成数据元素,数据元素组成数据
  17. IBM SPSS Modeler 14.1下载安装及注册详细教程
  18. 关于Rust读取自定义toml文件
  19. R语言Markowitz马克维茨投资组合理论分析和可视化
  20. what's the 头寸

热门文章

  1. c# picturebox控件显示本地图片和显示网上的图片
  2. zookeeper启动失败
  3. MongoDB学习之在Linux下安装MongoDB
  4. Eclipse导入Zookeeper源码Version2017.11.3
  5. python向自己qq邮箱发信息_python 向qq邮箱发邮件
  6. C# 将DataGridView里面的数据提取到DataTable中
  7. Implementation of the USB 3.0 controller not found!
  8. Javascipt超详细版思维导图+基础语法导航
  9. STL(八)——向量vector
  10. 记录第一次使用linux部署springbootweb项目