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

创建型模式--1.单例模式【巴基速递】

1. 巴基的订单

在海贼世界中,巴基速递是巴基依靠手下强大的越狱犯兵力,组建的集团海贼派遣公司,它的主要业务是向世界有需要的地方输送雇佣兵(其实是不干好事儿)。

在这里插入图片描述

自从从特拉法尔加罗路飞同盟击败了堂吉诃德家族 ,战争的市场对雇佣兵的依赖越来越大。订单便源源不断的来了。此时我们来分析一个问题:巴基是怎么接单并且派单的呢?

简单来说,巴基肯定是有一个账本用于记录下单者信息,下单者的需求以及下单的时间,然后根据下单的先后顺序选择合适的人手进行派单。从程序猿的视角可以这样认为,这个账本其实就相当于一个任务队列:

  • 有一定的容量,可以存储任务
  • 按照下单的先后顺序存储并处理任务 – 典型的队列特性:先进先出

对于巴基来说把所有的订单全部记录到一个账本上就够了,如果将其平移到项目中,也就意味着应用程序在运行过程中存储任务的任务队列一个足矣,弄太多反而冗余,不太好处理了。

在一个项目中,全局范围内,某个类的实例有且仅有一个,通过这个唯一实例向其他模块提供数据的全局访问,这种模式就叫单例模式。单例模式的典型应用就是任务队列。

在这里插入图片描述

2. 独生子女

如果使用单例模式,首先要保证这个类的实例有且仅有一个,也就是说这个对象是独生子女,如果我们实施计划生育只生一个孩子,不需要也不能给再他增加兄弟姐妹。因此,就必须采取一系列的防护措施。对于类来说以上描述同样适用。涉及一个类多对象操作的函数有以下几个:

  • 构造函数:创建一个新的对象
  • 拷贝构造函数:根据已有对象拷贝出一个新的对象
  • 拷贝赋值操作符重载函数:两个对象之间的赋值

为了把一个类可以实例化多个对象的路堵死,可以做如下处理:

  1. 构造函数私有化,在类内部只调用一次,这个是可控的。
  • 由于使用者在类外部不能使用构造函数,所以在类内部创建的这个唯一的对象必须是静态的,这样就可以通过类名来访问了,为了不破坏类的封装,我们都会把这个静态对象的访问权限设置为私有的。
  • 在类中只有它的静态成员函数才能访问其静态成员变量,所以可以给这个单例类提供一个静态函数用于得到这个静态的单例对象。
  1. 拷贝构造函数私有化或者禁用(使用 = delete

  2. 拷贝赋值操作符重载函数私有化或者禁用(从单例的语义上讲这个函数已经毫无意义,所以在类中不再提供这样一个函数,故将它也一并处理一下。

由于单例模式就是给类创建一个唯一的实例对象,所以它的UML类图是很简单的:
在这里插入图片描述

因此,定义一个单例模式的类的示例代码如下:

// 定义一个单例模式的类
class Singleton
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有Singleton(const Singleton& obj) = delete;Singleton& operator=(const Singleton& obj) = delete;static Singleton* getInstance();
private:Singleton() = default;static Singleton* m_obj;
};

在实现一个单例模式的类的时候,有两种处理模式:

  • 饿汉模式
  • 懒汉模式

3. 饿汉模式

饿汉模式就是在类加载的时候立刻进行实例化,这样就得到了一个唯一的可用对象。关于这个饿汉模式的类的定义如下:

// 饿汉模式
class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){return m_taskQ;}
private:TaskQueue() = default;static TaskQueue* m_taskQ;
};
// 静态成员初始化放到类外部处理
TaskQueue* TaskQueue::m_taskQ = new TaskQueue;int main()
{TaskQueue* obj = TaskQueue::getInstance();
}

第17行,定义这个单例类的时候,就把这个静态的单例对象创建出来了。当使用者通过getInstance()获取这个单例对象的时候,它已经被准备好了。

注意事项:类的静态成员变量在使用之前必须在类的外部进行初始化才能使用。

4. 懒汉模式

懒汉模式是在类加载的时候不去创建这个唯一的实例,而是在需要使用的时候再进行实例化。

4.1 懒汉模式类的定义

// 懒汉模式
class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){if(m_taskQ == nullptr){m_taskQ = new TaskQueue;}return m_taskQ;}
private:TaskQueue() = default;static TaskQueue* m_taskQ;
};
TaskQueue* TaskQueue::m_taskQ = nullptr;

在调用getInstance()函数获取单例对象的时候,如果在单线程情况下是没有什么问题的,如果是多个线程,调用这个函数去访问单例对象就有问题了。假设有三个线程同时执行了getInstance()函数,在这个函数内部每个线程都会new出一个实例对象。此时,这个任务队列类的实例对象不是一个而是3个,很显然这与单例模式的定义是相悖的。

4.2 线程安全问题

双重检查锁定

对于饿汉模式是没有线程安全问题的,在这种模式下访问单例对象的时候,这个对象已经被创建出来了。要解决懒汉模式的线程安全问题,最常用的解决方案就是使用互斥锁。可以将创建单例对象的代码使用互斥锁锁住,处理代码如下:

class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){m_mutex.lock();if (m_taskQ == nullptr){m_taskQ = new TaskQueue;}m_mutex.unlock();return m_taskQ;}
private:TaskQueue() = default;static TaskQueue* m_taskQ;static mutex m_mutex;
};
TaskQueue* TaskQueue::m_taskQ = nullptr;
mutex TaskQueue::m_mutex;

在上面代码的10~13 行这个代码块被互斥锁锁住了,也就意味着不论有多少个线程,同时执行这个代码块的线程只能是一个(相当于是严重限行了,在重负载情况下,可能导致响应缓慢)。我们可以将代码再优化一下:

class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){if (m_taskQ == nullptr){m_mutex.lock();if (m_taskQ == nullptr){m_taskQ = new TaskQueue;}m_mutex.unlock();}return m_taskQ;}
private:TaskQueue() = default;static TaskQueue* m_taskQ;static mutex m_mutex;
};
TaskQueue* TaskQueue::m_taskQ = nullptr;
mutex TaskQueue::m_mutex;

改进的思路就是在加锁、解锁的代码块外层有添加了一个if判断(第9行),这样当任务队列的实例被创建出来之后,访问这个对象的线程就不会再执行加锁和解锁操作了(只要有了单例类的实例对象,限行就解除了),对于第一次创建单例对象的时候线程之间还是具有竞争关系,被互斥锁阻塞。上面这种通过两个嵌套的 if 来判断单例对象是否为空的操作就叫做双重检查锁定

双重检查锁定的问题

假设有两个线程A、B,当线程A 执行到第 8 行时在线程A中 TaskQueue 实例对象 被创建,并赋值给 m_taskQ

static TaskQueue* getInstance()
{if (m_taskQ == nullptr){m_mutex.lock();if (m_taskQ == nullptr){m_taskQ = new TaskQueue;}m_mutex.unlock();}return m_taskQ;
}

但是实际上 m_taskQ = new TaskQueue; 在执行过程中对应的机器指令可能会被重新排序。正常过程如下:

  • 第一步:分配内存用于保存 TaskQueue 对象。
  • 第二步:在分配的内存中构造一个 TaskQueue 对象(初始化内存)。
  • 第三步:使用 m_taskQ 指针指向分配的内存。

但是被重新排序以后执行顺序可能会变成这样:

  • 第一步:分配内存用于保存 TaskQueue 对象。
  • 第二步:使用 m_taskQ 指针指向分配的内存。
  • 第三步:在分配的内存中构造一个 TaskQueue 对象(初始化内存)。

这样重排序并不影响单线程的执行结果,但是在多线程中就会出问题。如果线程A按照第二种顺序执行机器指令,执行完前两步之后失去CPU时间片被挂起了,此时线程B在第3行处进行指针判断的时候m_taskQ 指针是不为空的,但这个指针指向的内存却没有被初始化,最后线程 B 使用了一个没有被初始化的队列对象就出问题了(出现这种情况是概率问题,需要反复的大量测试问题才可能会出现)。

在C++11中引入了原子变量atomic,通过原子变量可以实现一种更安全的懒汉模式的单例,代码如下:

class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){TaskQueue* queue = m_taskQ.load();  if (queue == nullptr){// m_mutex.lock();  // 加锁: 方式1lock_guard<mutex> locker(m_mutex);  // 加锁: 方式2queue = m_taskQ.load();if (queue == nullptr){queue = new TaskQueue;m_taskQ.store(queue);}// m_mutex.unlock();}return queue;}void print(){cout << "hello, world!!!" << endl;}
private:TaskQueue() = default;static atomic<TaskQueue*> m_taskQ;static mutex m_mutex;
};
atomic<TaskQueue*> TaskQueue::m_taskQ;
mutex TaskQueue::m_mutex;int main()
{TaskQueue* queue = TaskQueue::getInstance();queue->print();return 0;
}

上面代码中使用原子变量atomicstore() 方法来存储单例对象,使用load() 方法来加载单例对象。在原子变量中这两个函数在处理指令的时候默认的原子顺序是memory_order_seq_cst(顺序原子操作 - sequentially consistent),使用顺序约束原子操作库,整个函数执行都将保证顺序执行,并且不会出现数据竞态(data races),不足之处就是使用这种方法实现的懒汉模式的单例执行效率更低一些

静态局部对象

在实现懒汉模式的单例的时候,相较于双重检查锁定模式有一种更简单的实现方法并且不会出现线程安全问题,那就是使用静态局部局部对象,对应的代码实现如下:

class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){static TaskQueue taskQ;return &taskQ;}void print(){cout << "hello, world!!!" << endl;}private:TaskQueue() = default;
};int main()
{TaskQueue* queue = TaskQueue::getInstance();queue->print();return 0;
}

在程序的第 9、10 行定义了一个静态局部队列对象,并且将这个对象作为了唯一的单例实例。使用这种方式之所以是线程安全的,是因为在C++11标准中有如下规定,并且这个操作是在编译时由编译器保证的:

如果指令逻辑进入一个未被初始化的声明变量,所有并发执行应当等待该变量完成初始化。

最后总结一下懒汉模式和饿汉模式的区别:

懒汉模式的缺点是在创建实例对象的时候有安全问题,但这样可以减少内存的浪费(如果用不到就不去申请内存了)。饿汉模式则相反,在我们不需要这个实例对象的时候,它已经被创建出来,占用了一块内存。对于现在的计算机而言,内存容量都是足够大的,这个缺陷可以被无视。

5. 替巴基写一个任务队列

作为程序猿的我们,如果想给巴基的账本升级成一个应用程序,首要任务就是设计一个单例模式的任务队列,那么就需要赋予这个类一些属性和方法:

  1. 属性:
    • 存储任务的容器,这个容器可以选择使用STL中的队列(queue)
    • 互斥锁,多线程访问的时候用于保护任务队列中的数据
  2. 方法:主要是对任务队列中的任务进行操作
    • 任务队列中任务是否为空
    • 往任务队列中添加一个任务
    • 从任务队列中取出一个任务
    • 从任务队列中删除一个任务

根据分析,就可以把这个饿汉模式的任务队列的单例类定义出来了:

#include <iostream>
#include <queue>
#include <mutex>
#include <thread>
using namespace std;class TaskQueue
{
public:// = delete 代表函数禁用, 也可以将其访问权限设置为私有TaskQueue(const TaskQueue& obj) = delete;TaskQueue& operator=(const TaskQueue& obj) = delete;static TaskQueue* getInstance(){return &m_obj;}// 任务队列是否为空bool isEmpty(){lock_guard<mutex> locker(m_mutex);bool flag = m_taskQ.empty();return flag;}// 添加任务void addTask(int data){lock_guard<mutex> locker(m_mutex);m_taskQ.push(data);}// 取出一个任务int takeTask(){lock_guard<mutex> locker(m_mutex);if (!m_taskQ.empty()){return m_taskQ.front();}return -1;}// 删除一个任务bool popTask(){lock_guard<mutex> locker(m_mutex);if (!m_taskQ.empty()){m_taskQ.pop();return true;}return false;}
private:TaskQueue() = default;static TaskQueue m_obj;queue<int> m_taskQ;mutex m_mutex;
};
TaskQueue TaskQueue::m_obj;int main()
{thread t1([]() {TaskQueue* taskQ = TaskQueue::getInstance();for (int i = 0; i < 100; ++i){taskQ->addTask(i + 100);cout << "+++push task: " << i + 100 << ", threadID: " << this_thread::get_id() << endl;this_thread::sleep_for(chrono::milliseconds(500));}});thread t2([]() {TaskQueue* taskQ = TaskQueue::getInstance();this_thread::sleep_for(chrono::milliseconds(100));while (!taskQ->isEmpty()){int data = taskQ->takeTask();cout << "---take task: " << data << ", threadID: " << this_thread::get_id() << endl;taskQ->popTask();this_thread::sleep_for(chrono::seconds(1));}});t1.join();t2.join();
}

在上面的程序中有以下几点需要说明一下:

  • 正常情况下,任务队列中的任务应该是一个函数指针(这个指针指向的函数中有需要执行的任务动作),此处进行了简化,用一个整形数代替了任务队列中的任务。
  • 任务队列中的互斥锁保护的是单例对象的中的数据也就是任务队列中的数据,上面所说的线程安全指的是在创建单例对象的时候要保证这个对象只被创建一次,和此处完全是两码事儿,需要区别看待。

相关文章:

创建型模式--1.单例模式【巴基速递】

1. 巴基的订单 在海贼世界中&#xff0c;巴基速递是巴基依靠手下强大的越狱犯兵力&#xff0c;组建的集团海贼派遣公司&#xff0c;它的主要业务是向世界有需要的地方输送雇佣兵&#xff08;其实是不干好事儿&#xff09;。 自从从特拉法尔加罗和路飞同盟击败了堂吉诃德家族 &…...

用 Wireshark 解码 H.264

H264&#xff0c;你不知道的小技巧-腾讯云开发者社区-腾讯云 这篇文章写的非常好 这里仅做几点补充 init.lua内容&#xff1a; -- Set enable_lua to false to disable Lua support. enable_lua trueif not enable_lua thenreturn end-- If false and Wireshark was start…...

鸿蒙TypeScript学习第10天:【String(字符串)】

1、TypeScript String&#xff08;字符串&#xff09; String 对象用于处理文本&#xff08;字符串&#xff09;。 语法 var txt new String("string"); 或者更简单方式&#xff1a; var txt "string"; 2、String 对象属性 下表列出了 String 对象支…...

【201】Java8读取JSON树形结构并插入到MySQL数据库表中

我写了一个 maven 项目的 Demo&#xff0c;用来演示 JAVA8 如何读取 JSON 文件树形结构&#xff0c;并将这种树形结构保存到 MySQL 中。 json文件 city.json {"name": "山东省","sub": [{"name": "青岛市","sub"…...

AI“复活”:慰藉心灵还是触碰禁忌?一文看懂技术与伦理的较量|TodayAI

随着人工智能&#xff08;AI&#xff09;技术的迅猛发展&#xff0c;其应用领域也越来越广泛&#xff0c;不仅仅局限于数据分析、机器人自动化等传统领域&#xff0c;更是延伸到了一些人们曾经认为只存在于科幻小说中的领域。近年来&#xff0c;使用AI技术“复活”逝者的概念&a…...

Jackson @JsonUnwrapped注解扁平化 序列化反序列化数据

参考资料 Jackson 2.x 系列【7】注解大全篇三JsonUnwrapped 以扁平的数据结构序列化/反序列化属性Jackson扁平化处理对象 目录 一. 前期准备1.1 前端1.2 实体类1.3 Controller层 二. 扁平化序列反序列化数据2.1 序列化数据2.2 反序列化数据 三. 前缀后缀处理属性同名四. Map数…...

日期时间相关的类

分界线jdk8 jdk8之前和之后分别提供了一些日期和时间的类&#xff0c;推荐使用jdk8之后的日期和时间类 Date类型 这是一个jdk8之前的类型&#xff0c;其中有很多方法已经过时了&#xff0c;选取了一些没有过时的API //jdk1.8之前的日期 Date Date date new Date(); // 从1970年…...

微信小程序脚本的执行顺序

在小程序中的脚本执行顺序和浏览器中有所不同。 小程序的执行的入口文件是 app.js 。 并且会根据其中 require 的模块顺序决定文件的运行顺序&#xff0c;代码是一个 app.js 示例。 app.js /* a.js console.log(a.js) */ var a require(./a.js) console.log(app.js)/* b.js co…...

zabbix监控警告

监控概述 对服务的管理&#xff0c;不能仅限于可用性。 还需要服务可以安全、稳定、高效地运行。 监控的目的&#xff1a;早发现、早治疗。 被监控的资源类型&#xff1a; 公开数据&#xff1a;对外开放的&#xff0c;不需要认证即可获取的数据 私有数据&#xff1a;对外不…...

YOLOv9架构图分享

YOLOv9是YOLO (You Only Look Once)系列实时目标检测系统的最新迭代。它建立在以前的版本之上&#xff0c;结合了深度学习技术和架构设计的进步&#xff0c;以在目标检测任务中实现卓越的性能。通过将可编程梯度信息(PGI)概念与广义ELAN (GELAN)架构相结合&#xff0c;YOLOv9在…...

全自动封箱机的工作原理:科技与效率的完美结合

随着科技的不断发展&#xff0c;越来越多的自动化设备走进了我们的日常生活和工业生产中。其中&#xff0c;全自动封箱机作为物流包装领域的重要一环&#xff0c;凭借其高效、精准的工作性能&#xff0c;正逐渐成为提升生产效率、降低劳动成本的得力助手。星派就来与大家深入探…...

【管理咨询宝藏48】AA银行信息科技提升分析报告

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏48】AA银行信息科技提升分析报告 【格式】PPT版本&#xff0c;可编辑 【关键词】战略规划、商业分析、管理咨询 【强烈推荐】这是一套市面上非常…...

循序表实战——基于循序表的通讯录

前言&#xff1a;本篇文章主要是利用顺序表作为底层&#xff0c; 实现一个通讯录。偏向于应用&#xff0c; 对于已经学习过c的友友们可能没有难度了已经。没有学习过c的友友&#xff0c; 如果顺序表不会写&#xff0c; 或者说没有自己实现过&#xff0c; 请移步学习顺序表相关内…...

Java编程规范及最佳实践

文章目录 一、命名规范二、代码风格规范三、注释规范四、推荐的编程实践五、类和接口六、异常处理七、可见性八、并发九、代码复用十、代码组织和模块化十一、Java集合框架十二、输入验证十三、资源管理十四、文档和注释十五、测试和代码质量十六、代码可读性十七、性能优化十八…...

90天玩转Python—07—基础知识篇:Python中运算符详解

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…...

C语言 位域

C 语言的位域&#xff08;bit-field&#xff09;是一种特殊的结构体成员&#xff0c;允许我们按位对成员进行定义&#xff0c;指定其占用的位数。 如果程序的结构中包含多个开关的变量&#xff0c;即变量值为 TRUE/FALSE&#xff0c;如下&#xff1a; struct {unsigned int w…...

【LeetCode热题100】【技巧】颜色分类

题目链接&#xff1a;75. 颜色分类 - 力扣&#xff08;LeetCode&#xff09; 只需排序三种&#xff0c;可以记录0和1的个数&#xff0c;然后直接原地赋值 class Solution { public:void sortColors(vector<int> &nums) {int zero 0, one 0;for (auto &num: n…...

笔记本电脑win7 Wireless-AC 7265连不上wifi6

1.背景介绍 旧路由器连接人数有限&#xff0c;老旧&#xff0c;信号不稳定更换了新路由器&#xff0c;如 TL-XDR5430易展版用户电脑连不上新的WIFI网络了&#xff0c;比较着急 核心问题&#xff1a;有效解决笔记本连接wifi上网问题&#xff0c;方法不限 2.环境信息 Windows…...

Linux gcc day5粘滞位

粘滞位 背景&#xff1a;一定时在一个公共目录&#xff08;root创建&#xff09;下。进行临时文件的操作 Linux系统中有很多人&#xff0c;我们需要在一个公共目录下&#xff0c;进行临时文件的操作&#xff08;增删查改&#xff09; 创建一个根目录下的dir&#xff08;mytmp…...

单片机按键消抖常用的软硬件方法

一&#xff1a;什么是开关抖动&#xff1f; 当我们按下按钮或拨动开关或微动开关时&#xff0c;两个金属部件会接触以短路电源。但它们不会立即连接&#xff0c;而是金属部件在实际稳定连接之前连接和断开几次。释放按钮时也会发生同样的事情。这会导致误触发或多次触发&#…...

钉钉自建应用-下载excel(h5)

由于不同手机对于文件下载有不同的支持&#xff0c;而且文件路径也不一样&#xff0c;找起来十分的麻烦。所以&#xff0c;最好是找到一个都支持的方法。还好&#xff0c;钉钉官网提供了网盘&#xff0c;我们可把文件保存到钉钉自带的网盘&#xff0c;这样方便查找。 这里需要…...

用二八定律分析零售数据,不就更直观了吗?

20%的商品贡献了80%的销售金额&#xff0c;你会不会想知道这些商品的销售金额、毛利、销售金额累计占比、毛利累计占比&#xff0c;会不会想知道这些商品在各个门店的销售表现&#xff1f;看是否能进一步提高销售金额&#xff0c;提高毛利。这样的报表该怎么做&#xff1f;奥威…...

NetSuite Saved Search-当前库存快照查询报表(二)

之前第一篇文章我们说明了&#xff0c;如何利用Saved Search来制作一个能够显示批次物料与非批次物料的Lot信息以及On Hand在手数量的“当前库存快照查询报表”&#xff0c;但是当用户提出“我们能否再加上批次物料的效期”需求时&#xff0c;我们原有的Saved Search并不能达到…...

【JavaSE】接口 详解(上)

前言 本篇会讲到Java中接口内容&#xff0c;概念和注意点可能比较多&#xff0c;需要耐心多看几遍&#xff0c;我尽可能的使用经典的例子帮助大家理解~ 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 前言 接口 语法…...

嵌入式C基础——循环队列 ringbuffer 讲解

本期主题&#xff1a; 讲解ARRAY_SIZE的作用以及定义&#xff0c;还有一个踩坑分析 往期链接&#xff1a; 数据结构系列——先进先出队列queue数据结构系列——栈 stackLinux内核链表零长度数组的使用inline的作用嵌入式C基础——ARRAY_SIZE使用以及踩坑分析 目录 1. Ringbuff…...

【动态规划-状态压缩dp】【蓝桥杯备考训练】:毕业旅行问题、蒙德里安的梦想、最短Hamilton路径、国际象棋、小国王【已更新完成】

目录 1、毕业旅行问题&#xff08;今日头条2019笔试题&#xff09; 2、蒙德里安的梦想&#xff08;算法竞赛进阶指南&#xff09; 3、最短Hamilton路径&#xff08;《算法竞赛进阶指南》&模板&#xff09; 4、国际象棋&#xff08;第十二届蓝桥杯省赛第二场C A组/B组&#…...

全坚固笔记本丨工业笔记本丨三防笔记本相较于普通笔记本有哪些优势?

三防笔记本和普通笔记本在设计和性能方面存在显著差异&#xff0c;三防笔记本相较于普通笔记本具备以下优势&#xff1a; 三防笔记本通常采用耐磨、耐摔的材料&#xff0c;并具有坚固的外壳设计&#xff0c;能够承受恶劣环境和意外碰撞&#xff0c;有效保护内部组件不受损坏。相…...

机房搬迁方案

一、项目背景 随着XX公司业务的不断扩展&#xff0c;现有的机房设备已经无法满足日益增长的数据处理需求。同时&#xff0c;考虑到现有机房的设施老化及潜在的安全隐患&#xff0c;XX公司决定进行机房搬迁。本次搬迁旨在确保业务连续性、数据安全性以及新机房的高效运营。 二…...

推动科技创新润德生物邀您到场参观2024第13届生物发酵展

参展企业介绍 山东润德生物科技有限公司成立于2014年10月17日&#xff0c;是一家围绕生物制品的研发、生产、营销、国际贸易、技术服务为核心业务的国家高新技术企业&#xff0c;近年来荣获国家制造业单项冠军示范企业、国家级绿色工厂、国家知识产权优势企业、国家工业产品绿…...

如何在JavaScript中提高性能

在JavaScript中提高性能是一个涉及多个方面的任务&#xff0c;包括代码优化、数据结构选择、异步编程、避免全局查找、内存管理等。以下是一些关键的策略和技巧&#xff0c;可以帮助你提高JavaScript代码的性能&#xff1a; 1. 优化循环 使用for循环代替forEach&#xff0c;特…...

wordpress登录不上去/子域名网址查询

直流电源防反接技术汇总 http://www.ejiguan.cn/2021/changjianwtjd_0324/3177.html 支持原创。...

网站开发职业资格证书/专业做seo推广

如今&#xff0c;手机已经成为人们日常生活必不可少的工具之一。虽然各种社交APP层次不穷&#xff0c;但手机短信以其操作简单、方便快捷等诸多优点一直都是用户间沟通的基础方式。手机短信在为人们带来极大便利的同时&#xff0c;随之而来的诸多垃圾短信问题日益严峻&#xff…...

e通网网站建设/线上推广的方式

使用axios的两种调用方式 1.安装axios $ cnpm install axios 2.在vue入口文件main.js中引入(推荐全局引入)&#xff0c;或是在当前页面中引入(局部) import axios from axios; 方法一&#xff1a; 在页面中直接调用&#xff0c;代码如下&#xff1a; new Vue({el: #app,data ()…...

北戴河区建设局网站/网络推广方法有几种

lvgl官方的教程是英文的&#xff0c;这个是我在做项目时根据lvgl官方文档做出来的lvgl中文文档(持续更新维护)&#xff0c;不仅仅只是生硬照搬lvgl官方文档的翻译&#xff0c;同时总结了我们在实际开发中遇到的各种细节&#xff0c;让这个文档更加适合我们在实际开发中的需求。…...

想创业做网站/游戏推广员平台

什么是RMI&#xff1a; RMI是远程方法调用(Remote Method Invocation)。能够让在某个Java虚拟机上的对象像调用本地对象一样调用另一个Java 虚拟机中的对象上的方法。将网络通讯和并发控制对程序开发人员透明化&#xff0c;那么将极度简化此类应用的开发成本&#xff0c;RMI就是…...

合网站建设/扬州网站seo

​都说项目经理压力大、上升困难&#xff0c;很多高级项目经理在后期都感觉“动力不足”&#xff0c;明明已经很拼命地工作了&#xff0c;为什么越到后面越难取得突破性的成就&#xff1f;眼看着年纪变大&#xff0c;职位却止步不前。 在和一些资深的项目总监交流后&#xff0c…...