当前位置: 首页 > news >正文

单列模式1.0

单列模式

单例模式能保证某个类在程序中只存在唯⼀⼀份实例, ⽽不会创建出多个实例

1.饿汉模式
只要程序一启动就会立即创建出一个对象

class Signleton{private static Signleton instance=new Signleton();//防止在以后的代码中再创建对象,我们将构造方法private,private Signleton(){}public static Signleton getInstance(){return instance;}
}

注意虽然构造方法是private,但是我们仍然可以在类外面用反射拿到私有构造方法,创建实例

如果在代码中存在多个单例类,饿汉模式在程序启动的时候就会发生扎堆创建,延缓了程序启动时间。

2.懒汉模式
只有在调用的时候才会创建对象

class SingletonLazy {private static volatile SingletonLazy instance=null;private SingletonLazy(){}public static void getInstance(){if(instance==null){synchronized (SingletonLazy.class){if(instance==null){instance=new SingletonLazy();}}}}}

懒汉模式进阶

class Singleton {
//在这里我们加入volatile,第一点为了内存可见性问题,第二点为了指令重排序问题private static volatile Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

在这里插入图片描述
假设有两个线程,t1,t2.线程之间是强占是执行的,t1,t2都通过第一层判断(instance==null),假设t1拿到锁,在t1执行完返回一个instance,这是instance不再是null,所以在t1线程释放锁后,t2线程将不再进入第二层的判断,故这个对象只创建了一次。这种双重if就避免了重复创建对象

指令重排序问题

在这里插入图片描述
此程序代码大体可以三个步骤:
1.申请内存空间
2.调用构造方法
3.把此时内存空间的地址,幅值给instance引用

如上图在t1和t2线程中,如果在t1线程执行了第一步和第二步,没有把第三步执行完就去执行线程t2,此时instance这个引用已经不为空了,也就是说返回创建的对象根本就没有创建好。

阻塞队列

在 Java 标准库中内置了阻塞队列. 如果我们需要在⼀些程序中使⽤阻塞队列, 直接使⽤标准库中的即

阻塞队列相比较于普通队列和优先级队列来说,线程是安全的,而其他两个线程是不安全的

  • BlockingQueue 是⼀个接⼝. 真正实现的类LinkedBlockingQueue.
  • put ⽅法⽤于阻塞式的⼊队列, take ⽤于阻塞式的出队列.
  • BlockingQueue 也有 offer, poll, peek 等⽅法, 但是这些⽅法不带有阻塞特性.可.
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
// ⼊队列
queue.put("abc");
// 出队列. 如果没有 put 直接 take, 就会阻塞. 
String elem = queue.take();

这种就阻塞了

public class demo2 {public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue=new ArrayBlockingQueue<>(1000);queue.put("aaa");String elem= queue.take();System.out.println("elem="+elem);queue.take();}
}

用阻塞队列实现消费者模型

    public static void main(String[] args) throws InterruptedException {BlockingQueue<Integer> blockingQueue=new LinkedBlockingQueue<>();Thread custom=new Thread(()->{while (true){try {int value= blockingQueue.take();System.out.println("消费者:"+value);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"消费者");custom.start();Thread producer=new Thread(()->{Random random=new Random();while (true){try {int num=random.nextInt(1000);blockingQueue.put(num);System.out.println("生产者:"+num);Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"生产者");producer.start();custom.join();producer.join();}
}

消费者模型有很多优势,其中两个最重要的是
1.解耦合(线程只关心与队列的交互,不用管线程之间的交互)
2.削峰填谷(大概意思就是假如是两个线程,这两个线程相互制约,以最慢的为准,你生产一个我去消费一个)
在这里插入图片描述

http://www.lryc.cn/news/337963.html

相关文章:

  • golang kafka sarama源码分析
  • 计算机组成原理【CO】Ch2 数据的表示和应用
  • dfs回溯 -- Leetcode46. 全排列
  • 设计模式-接口隔离原则
  • BD202311夏日漫步(最少步数,BFS或者 Dijstra)
  • React - 你知道props和state之间深层次的区别吗
  • mysql 查询实战-变量方式-解答
  • SpringBoot3配置SpringSecurity6
  • Unity之Unity面试题(三)
  • Linux命令-dos2unix命令(将DOS格式文本文件转换成Unix格式)
  • 企业怎么做数据分析
  • 1111111111
  • [面向对象] 单例模式与工厂模式
  • 《前端防坑》- JS基础 - 你觉得typeof nullValue === null 么?
  • 【项目实战经验】DataKit迁移MySQL到openGauss(下)
  • AI预测体彩排3第2弹【2024年4月13日预测--第1套算法开始计算第2次测试】
  • 【13137】质量管理(一)2024年4月串讲题组一
  • Go语言中工作负载类型对并发的影响
  • 常用的Python内置函数
  • MAC(M1芯片)编译Java项目慢且发热严重问题解决方案
  • 如何循环pandas格式的数据
  • 新零售SaaS架构:客户管理系统架构设计(万字图文总结)
  • Apache Spark
  • CentOS7编译ZLMediaKit并使能WebRTC
  • 【数据交换格式】网络socket编程温度采集智能存储与上报项目技术------JSON、TLV
  • IP地址定位技术在各领域的作用
  • 代码随想录 538. 把二叉搜索树转换为累加树
  • JavaWeb--前端--01HTML和CSS
  • Oracle SQL中的DECODE函数与NVL函数:区别与应用场景详析
  • 算法设计与分析实验报告c++实现(N皇后问题、卫兵布置问题、求解填字游戏问题、图的m着色问题)