【JavaEE】单例模式和阻塞队列
🔥个人主页: 中草药
🔥专栏:【Java】登神长阶 史诗般的Java成神之路
🕯️一.设计模式
在Java中,设计模式(Design Patterns)是指在软件工程和面向对象编程中,针对特定问题和常见情境的一种经过验证的解决方案模板。设计模式不是具体的代码,而是一种描述问题和解决方案的通用形式,它提供了一种在软件设计中重复使用的方法,一种固定套路,帮助开发者以更优雅、更灵活的方式解决常见的设计问题,从而提高代码的可读性、可维护性和可扩展性。
设计模式通常基于以下几个方面:
- 目的:解决某一类问题或实现特定的功能。
- 参与者:涉及的类和对象。
- 协作:这些类和对象之间的交互方式。
- 效果:使用模式后带来的好处和可能的权衡。
设计模式通常被分类为三种类型:
-
创建型模式(Creational Patterns):关注对象的创建机制,试图创建对象的过程能够满足一定的约束条件,例如单例模式(Singleton)、工厂模式(Factory)、抽象工厂模式(Abstract Factory)、建造者模式(Builder)和原型模式(Prototype)。
-
结构型模式(Structural Patterns):关注类和对象的组合,以达到更灵活和可复用的结构,例如适配器模式(Adapter)、装饰模式(Decorator)、代理模式(Proxy)、桥接模式(Bridge)、组合模式(Composite)和外观模式(Facade)。
-
行为型模式(Behavioral Patterns):关注类和对象之间的职责分配和交互,涉及算法的封装和对象之间的通信,例如策略模式(Strategy)、模板方法模式(Template Method)、观察者模式(Observer)、命令模式(Command)、迭代器模式(Iterator)、访问者模式(Visitor)、中介者模式(Mediator)和状态模式(State)。
不同的设计模式的使用可以带来以下优势:
- 代码复用:通过模式,可以复用解决问题的方案,避免重复造轮子。
- 可维护性:模式往往伴随着良好的代码组织,使得代码更易于理解和维护。
- 可扩展性:模式鼓励使用接口和抽象类,使得系统更易于扩展和修改。
- 灵活性:模式强调松耦合,使得系统更加灵活,能够适应变化。
设计模式并非万能药,过度使用或不恰当使用设计模式可能导致代码过度复杂,增加理解难度。因此,在应用设计模式时,应根据实际情况和项目需求,灵活选择最合适的模式。
在这里,我们着重来学习单例模式和阻塞队列
📽️二.单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。这种模式在需要频繁创建和销毁对象开销较大,或者某个资源只能由一个实例独占使用的场景中非常有用。单例模式通常用于创建日志对象、对话框、数据库连接、配置管理器等。
1.单例模式的实现
单例模式的主要目标是控制一个类的实例化过程,确保任何时候都只有一个实例存在,并且提供一个全局访问点。以下是几种常见的实现方式:
-
懒汉式(Lazy Initialization): 这是最直观的实现方式,只有在首次请求实例时才创建实例。
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;} }
但是,上面的代码在多线程环境下可能不是线程安全的,因为多个线程可能同时进入
if
语句判断,导致创建多个实例。改进的版本可以使用双重检查锁定(Double-Checked Locking):class SingletonLan{private static volatile SingletonLan instance=null;//1.volatile内存可见性问题private SingletonLan() {}public static SingletonLan getInstance() {if (instance==null){//2.判断是否要加锁synchronized (locker) {//3.加锁,把if判定和new赋值操作打包成原子操作if (instance == null) {//4.是否要创建对象instance = new SingletonLan();}}}return instance;} }
-
饿汉式(Eager Initialization): 这种方式在类加载时就创建实例,因此不存在多线程安全问题。
public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;} }
除此之外还有静态内部类实现(这种方式结合了懒汉式的延迟加载和饿汉式的线程安全,利用了Java类加载机制保证初始化实例时只有一个线程。) 以及《Effective Java》作者Joshua Bloch推荐的枚举方式,简洁并且线程安全。
2.优缺点
优点:
- 确保一个类只有一个实例,节省内存和资源。
- 全局唯一访问点,便于控制和扩展。
缺点:
- 单例模式可能会隐藏类之间的依赖关系,因为单例类的实例是静态的,不容易在代码中显式表达。
- 单例模式可能违反单一职责原则,一个类负责实例的创建和管理,同时也负责业务逻辑。
- 在多线程环境下,实现线程安全的单例模式需要额外的注意和开销。
单例模式是一种强大的设计模式,可以有效地控制资源的使用,特别是在多线程和网络环境中。然而,它也有可能引入一些不易察觉的问题,因此在使用时应当谨慎,并充分考虑具体的应用场景和潜在的影响。
💡 三.阻塞队列
1.生产者消费者模型
生产者消费者模型是计算机科学中用于解决多线程或并发编程中资源分配和数据共享问题的经典模型。这个模型主要用于描述一组生产数据的进程(或线程)和一组消费这些数据的进程(或线程)之间的交互。它是实现资源管理、数据缓冲和流程控制的有效方式,特别是在多线程和分布式系统中。
基本概念
在生产者消费者模型中,有两组主要的角色:
- 生产者(Producer):负责生成数据或资源,并将它们放入一个共享容器(如队列、缓冲区)中。
- 消费者(Consumer):负责从共享容器中取出数据或资源,并对其进行处理。
这两个角色通过一个共享的缓冲区或队列进行通信和数据交换。生产者将数据放入队列,而消费者从队列中取出数据进行处理。
工作流程
生产者消费者模型的工作流程如下:
-
生产者向队列中添加数据:当生产者生成数据时,它会尝试将数据放入队列中。如果队列已满,生产者可能需要等待,直到有空间可用。
-
消费者从队列中移除数据:当消费者准备好处理数据时,它会从队列中取出数据。如果队列为空,消费者可能需要等待,直到队列中有数据可用。
-
同步和通信:为了确保数据的正确处理,生产者和消费者必须通过某种机制(如锁、信号量或条件变量)进行同步,以避免数据竞争和不一致性。
解决的问题
生产者消费者模型解决了以下问题:
- 资源竞争:通过使用同步机制,可以防止生产者和消费者同时访问共享资源,从而避免数据的混乱或丢失。
- 缓冲区管理:队列或缓冲区充当了生产者和消费者之间的中间层,可以吸收生产速率和消费速率之间的差异,避免生产者和消费者的直接耦合。
- 并发控制:模型允许并发执行,提高系统的吞吐量和响应速度。
实现细节
在实际编程中,实现生产者消费者模型通常涉及到以下技术:
- 线程和进程:生产者和消费者可以是不同的线程或进程。
- 同步原语:使用互斥锁(mutex)、信号量(semaphore)、条件变量(condition variable)等来确保数据的正确性和一致性。
- 队列和缓冲区:实现数据的存储和传递,可以是基于数组、链表或其他数据结构的队列。
Java中的实现
在Java中,可以使用java.util.concurrent
包中的BlockingQueue
接口来实现生产者消费者模型,该接口提供了线程安全的队列实现,如ArrayBlockingQueue
、LinkedBlockingQueue
等,它们内置了阻塞机制,可以简化同步和通信的实现。
应用场景
生产者消费者模型广泛应用于各种场景,包括但不限于:
- 消息队列:如RabbitMQ、Kafka等,用于在微服务架构中解耦服务间的通信。
- 任务调度和执行框架:如Apache Airflow、Apache Beam等,用于大规模数据处理和分析任务的调度。
- 多媒体处理:在视频编码、音频流处理等场景中,用于处理连续的数据流。
- 游戏开发:在渲染引擎中,生产者可能负责生成游戏世界的帧,而消费者则负责渲染这些帧。
总之,生产者消费者模型是解决多线程和并发问题的一个强大工具,它通过分离数据的生产和消费过程,提高了系统的可扩展性和可靠性。
2.阻塞队列
在Java中,阻塞队列(Blocking Queue)是一种特殊类型的队列,它提供了额外的阻塞行为。通常,队列是一种先进先出(FIFO)的数据结构,其中元素的插入操作在队列的尾部进行,而移除操作在队列的头部进行。阻塞队列在标准队列的基础上增加了线程安全性和阻塞能力,使其成为多线程环境中处理任务的理想选择。
特点
// 创建一个容量为5的阻塞队列
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
阻塞队列的主要特点如下:
-
线程安全性:阻塞队列的所有方法都是线程安全的,这意味着多个线程可以同时访问队列而不会引起数据不一致的问题。
-
阻塞行为:当队列满时,
put
方法会阻塞调用线程,直到队列中有可用空间为止。同样,当队列空时,take
方法会阻塞调用线程,直到队列中有新元素被加入。这种阻塞行为有助于线程间的同步和通信。 -
容量限制:阻塞队列通常具有固定的容量限制,这有助于防止无限的内存消耗。
常见的阻塞队列类型
Java并发工具包(java.util.concurrent
包)提供了几种不同类型的阻塞队列实现,每种实现都有其独特的特性和适用场景:
-
ArrayBlockingQueue
:基于数组的有界阻塞队列。它使用公平锁和非公平锁两种模式,并且是线程安全的。 -
LinkedBlockingQueue
:基于链表的阻塞队列。它有两个构造器,一个是有界的,另一个是无界的。当使用无界构造器时,队列的大小只受限于系统可用的内存。 -
PriorityBlockingQueue
:基于优先级堆的无界阻塞队列。元素按优先级排序,当多个元素具有相同优先级时,它们按照FIFO顺序排列。 -
SynchronousQueue
:一种特殊的阻塞队列,它不存储元素,而是在生产者线程和消费者线程之间直接传递元素。这使得它非常轻量级,但不适合存储元素。 -
DelayQueue
:一种特殊类型的队列,它只保存延期元素。元素只有在其延迟过期后才能从队列中取出。
使用场景
阻塞队列广泛应用于多线程编程中,尤其在以下场景中:
-
线程池:线程池使用阻塞队列来管理待处理的任务,当线程空闲时,它们会从队列中获取任务来执行。
-
生产者-消费者模型:阻塞队列是实现生产者-消费者模式的理想选择,生产者向队列中添加元素,而消费者从队列中取出元素。
-
任务调度:阻塞队列可以用于任务的调度,比如定时任务或基于事件的任务。
-
资源池管理:例如数据库连接池或缓存池,阻塞队列可以用来管理有限的资源。
总结
阻塞队列是Java并发编程中一个非常重要的概念,它提供了一种线程安全且高效的机制来管理多线程环境下的任务调度和资源分配。通过选择合适的阻塞队列类型,可以有效地控制并发级别,提高系统的响应能力和吞吐量。
3.模拟实现
我们可以模拟一个基于数组的阻塞队列
实现代码
class MyBlockingQueue{private int head = 0;private int tail = 0;private int size = 0;private String[] data=null;public MyBlockingQueue(int capacity){data=new String[capacity];}public void put(String s) throws InterruptedException {synchronized(this){if (size==data.length){this.wait();//如果wait在try catch里面,// 此时应该用while 在wait唤醒之后判断是否继续执行 如t2}data[tail]=s;tail++;if (tail>=data.length){tail=0;}size++;this.notify();}}public String take() throws InterruptedException{String ret=null;synchronized(this){while (size==0){this.wait();}ret=data[head];head++;if (head>=data.length){head=0;}size--;this.notify();}return ret;}
}
测试代码
public static void main(String[] args) {MyBlockingQueue queue=new MyBlockingQueue(1000);Thread t1=new Thread(()->{int i=1;while(true){try {queue.put(i+"");System.out.println("生产元素:"+i);i++;Thread.sleep(1000);//生产慢点} catch (InterruptedException e) {e.printStackTrace();}}});Thread t2=new Thread(()->{while(true){try {int cur=Integer.parseInt(queue.take());System.out.println("取出元素:"+ cur);//Thread.sleep(1000);//生产快点,消费慢点} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();t2.start();}
测试结果
1.当生产慢于消费者时
2.当生产快于消费者时
🏮四.总结与反思
梦想家命长,实干家寿短。——约.奥赖利
在深入探索软件设计模式与多线程编程技术的过程中,Java中的单例模式与阻塞队列成为了我关注的焦点。这两个概念虽然分别属于设计模式和并发控制领域,但它们都在提高代码质量和系统性能方面扮演着关键角色。下面是对这两项技术的学习总结与个人反思。
单例模式(Singleton Pattern)
定义与目的: 单例模式是一种常用的软件设计模式,其核心目标是在整个系统中保证一个类只有一个实例,并提供一个全局访问点。这有助于节省资源,确保共享资源的一致性,比如数据库连接、配置管理器等。
实现方式:
- 懒汉式(Lazy Initialization):在首次使用时创建实例,适用于延迟加载的情况。
- 饿汉式(Eager Initialization):在类加载时就创建实例,适合于系统启动时就需要初始化的情况。
- 双重检查锁定(Double Checked Locking):结合懒汉式的延迟加载和同步控制,确保线程安全的同时减少锁的竞争。
反射与序列化挑战: 单例模式通过私有构造函数和静态工厂方法或枚举来实现,但反射和序列化可能会破坏单例性质。解决办法是重写clone
方法和readResolve
方法来保持单例的唯一性。
个人反思: 单例模式虽然简单,但在复杂系统中应用时需谨慎。过度使用可能导致系统变得难以测试和维护。同时,随着微服务架构的流行,单例模式的全局性也需要重新审视,因为它可能不再适用于分布式环境。
阻塞队列(Blocking Queue)
定义与目的: 阻塞队列是一种特殊的队列,它在队列满时阻止生产者线程继续添加元素,在队列空时阻止消费者线程取出元素,直到条件满足。这样可以有效控制线程间的同步,避免资源竞争和死锁问题。
应用场景:
- 生产者消费者模型:用于协调不同线程之间的数据传递,如任务调度、消息队列等。
- 限流与缓冲:在高并发场景下,阻塞队列可以作为缓冲区,防止后端系统过载。
Java中的实现:
ArrayBlockingQueue
:基于数组的阻塞队列,固定大小。LinkedBlockingQueue
:基于链表的阻塞队列,可选择固定或无限大小。PriorityBlockingQueue
:基于优先级堆的阻塞队列,适用于需要按优先级处理任务的场景。
个人反思: 阻塞队列的使用提升了系统的健壮性和可扩展性,尤其是在多线程环境下。然而,正确配置队列的大小和理解队列的阻塞机制至关重要,否则可能会导致性能瓶颈或资源浪费。此外,阻塞队列的灵活性也意味着开发者需要对线程的交互和队列的行为有深入的理解。
总结
学习单例模式和阻塞队列,不仅加深了我对Java语言特性的理解,也让我认识到在设计高效、健壮的系统时,选择合适的设计模式和并发控制策略的重要性。未来在开发项目时,我会更加注重模式的适用性和潜在的副作用,努力构建既灵活又稳定的软件架构。
🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀
以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐
制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸
相关文章:

【JavaEE】单例模式和阻塞队列
🔥个人主页: 中草药 🔥专栏:【Java】登神长阶 史诗般的Java成神之路 🕯️一.设计模式 在Java中,设计模式(Design Patterns)是指在软件工程和面向对象编程中,针对特定…...

RCE绕过技巧
目录 EVAL长度限制突破技巧 1.使用反引号 2.file_put_contents写入文件 3.php5.6变长参数usort回调后门 命令长度限制突破技巧 1.拼接文件名 无字母数字的webshell命令执行 1.取反码 2.上传临时文件 EVAL长度限制突破技巧 分析代码:首先传递一个param参数&…...

Spring源码解析(31)之事务配置文件解析以及核心对象创建过程
一、前言 首先我们先准备一下spring 事务的配置文件,具体内容如下: <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/20…...

win11安装docker报错记录
报错一: Docker Desktop - Unexpected WSL error An unexpected error occurred while executing a WSL command. Either shut down WSL down with wsl --shutdown, and/or reboot your machine. You can also try reinstalling WSL and/or Docker Desktop. If t…...

【vulnhub】CLAMP 1.0.1靶机
信息收集 靶机发现 端口扫描 页面访问,并查看源码 访问 /nt4stopc/,下面有一些问题,提示必须收集答案 一些判断题,对与错对应1与0,最后结果为0110111001,拼接访问 点击图中位置,发现存在参数,p…...

GPS跟踪环路MATLAB之——数字锁相环
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 GPS跟踪环路MATLAB之——数字锁相环 前言为什么要锁相环科斯塔斯环锁相环的一些基本概念1、捕获、锁定与跟踪的概念2、捕获时间和稳态相差3、相位捕获和频率捕获4、捕获带和同…...

docker开发环境搭建-关于数据库的IP是什么
故事的背景是这样的: 我在本地的ubuntu系统上安装了docker,并创建了一个mysql容器,但是在使用DBeaver连接该数据库时,需要填写数据库的ip,填写127.0.0.1,工具提示找不到这个库,然后使用ip addr…...

loginApi
import request from "/utils/request"; import { AxiosPromise } from "axios"; import { CaptchaResult, LoginData, LoginResult } from "./types";/*** 登录API** param data {LoginData}* returns*/ export function loginApi(data: LoginD…...

【RAG检索增强生成】Ollama+AnythingLLM本地搭建RAG大模型私有知识库
目录 前言一、Ollama:革新性的本地LLM服务工具1.核心优势2.技术亮点 二、AnythingLLM 概览1.核心特性2.技术生态支持 三、搭建本地智能知识库1. Ollama的安装启航2. AnythingLLM的安装对接3. AnythingLLM的配置精调4. 工作区与文档管理5. 聊天与检索的智能交互 四、…...

【wiki知识库】08.添加用户登录功能--前端Vue部分修改
🍊 编程有易不绕弯,成长之路不孤单! 目录 🍊 编程有易不绕弯,成长之路不孤单! 一、今日目标 二、前端Vue模块的修改 2.1 the-header组件 2.2 store工具 2.3 router路由配置修改 一、今日目标 上篇文章…...

写给非机器学习人员的 embedding 入门
你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等 希望看什么,评论或者私信告诉我! 文章目录 一…...

Oracle【plsql编写九九乘法表】
九九乘法表 DECLAREi NUMBER : 1;j NUMBER : 1; BEGINFOR i IN 1 .. 9LOOPFOR j IN 1 .. iLOOPDBMS_OUTPUT.put (i || * || j || || i * j || );END LOOP;DBMS_OUTPUT.put_line ( );END LOOP; END;输出结果...

ansible安装K8s
部署Kubernetes (k8s) 集群使用Ansible是一个常见的自动化解决方案。下面我将提供一个基本的步骤概述和所需的命令,用于在CentOS 7.8上使用Ansible部署k8s集群,包括Master节点和Worker节点(Web和DB节点)。 步骤 1: 准备环境 确保所…...

restful传值
GetMapping 普通的get请求 后端: restfule的get请求 通过/asd/123这种方式get请求传入后端 前端 url: /system/role/deptTree/ roleId / tenantId, method: get后端PathVariable从path上取对应的值 通过 GetMapping(value "/deptTree/{roleId}/{tenan…...

Qt自定义TreeWidget,实现展开折叠按钮在右侧,且一条竖直线上对齐
效果如下: 图片随便找的,可能需要调下样式,代码复制可用,留给有需要的人。 #ifndef CustomTreeWidget_h__ #define CustomTreeWidget_h__#include <QTreeWidget> #include <QPushButton>class CCustomTreeWidget : p…...

硅步千里:如何入行?——之入行成为软件开发者
无论何时,你是否有遇到这样的场景(在自己从未涉足过的行业或领域,现在需要自己去这个行业或领域学习探索,最初的目标是熟悉行业,快速融入进去,很多时候,我们只是了解了个大概,并没能…...

Sandbox: rsync.samba(80134) deny(1) file-write-create
Xcode15运行报错:Sandbox: rsync.samba(80134) deny(1) file-write-create/xxx/xxx 如下图: 解决办法: Build Settings 搜索 sandbox,把 Build Options 中的 User Script Sandboxing改为 NO...

lvs的dr模式综合实践
目录 编辑虚拟机准备工作 编辑编辑编辑 配置过程 配置client主机 配置router主机 配置lvs主机(vip使用环回来创建) 配置server1主机(vip使用环回来创建) 配置server2主机(vip使用环回来创建࿰…...

什么是自然语言处理
自然语言处理(Natural Language Processing, NLP)是人工智能(AI)的一个子领域,涉及计算机与人类语言的交互。它的目标是让计算机能够理解、分析、生成和操作自然语言,从而实现与人类的有效沟通。 自然语言处…...

快速理解互联网中的常用名词
并发与并行 并发:任务交替执行,伪并行,涉及CPU时间片和上下文切换。并行:任务真正同时执行,需要多核处理器,无上下文切换。 并发量(Concurrency) 概念:服务端程序单位…...

统计接口调用耗时_黑白名单配置
黑名单配置 黑名单就是那些被禁止访问的URL创建自定义过滤器 BlackListUrlFilter,并配置黑名单地址列表blacklistUrl如果有其他需求,还可以实现自定义规则的过滤器来满足特定的过滤要求 /*** 黑名单过滤器** author canghe*/ Component public class B…...

树莓派4 AV没有视频输出
使用AV接口输出,没有画面 需要在config.txt文件中 增加配置 enable_tvout1config.txt 中的 dtoverlayvc4-kms-v3d 行末尾添加,composite: dtoverlayvc4-kms-v3d,composite默认情况下,输出 NTSC 复合视频。要选择不同的模式,请在…...

短信群发平台:解决短信验证码接收问题的5大策略
在享受数字化服务时,如APP注册或网站登录,若遇到短信验证码无法接收的困扰,无疑会增添不少烦恼。为了帮助您迅速解决这一问题,我们精心总结了以下十大原因及对应的解决方法,助您顺畅完成验证流程。 一、优化网络环境 …...

WebSocket 初体验:构建实时通信应用
WebSocket是一种在客户端和服务器之间建立持久连接的协议,它允许双方进行双向通信,从而实现低延迟的数据交换。WebSocket非常适合需要实时交互的应用场景,比如聊天应用、在线游戏、实时数据分析等。 WebSocket简介 什么是WebSocket…...

LISA: Reasoning Segmentation via Large Language Model
发表时间:CVPR 2024 论文链接:https://openaccess.thecvf.com/content/CVPR2024/papers/Lai_LISA_Reasoning_Segmentation_via_Large_Language_Model_CVPR_2024_paper.pdf 作者单位:CUHK Motivation:尽管感知系统近年来取得了显…...

企业发展与数字化转型:创新驱动未来增长的关键策略
引言 在当今全球化和信息化高度融合的时代,数字化转型已经成为企业寻求增长和保持竞争优势的关键战略。随着技术的飞速进步,数字化不仅改变了商业模式和市场格局,还深刻影响了企业的内部运作和外部生态系统。大数据、人工智能、物联网等新兴技…...

如何选择适合自己的编程语言,为什么R是非计算机专业数据分析的最佳选择,五大点告诉你
在如今的数据驱动世界中,编程语言已成为希望在行业中进行数据分析的专业人士不可或缺的技能。对于非计算机专业背景的学者和学生来说,选择适合自己的编程语言可能看似困难。本文将探讨为什么对于那些需要进行本科生论文、研究生论文、或者发表学术成果的…...

【经验分享】数据结构——求树的叶子结点个数计算方法
目录 一道题就可以学会 这种题做法固定,记住两个公式即可 解惑: 1、为什么n2010110x? 2、为什么是n-120*410*31*210*1x*0? 🌈 嗨,我是命运之光! 🌌 2024,每日百字&…...

第十一章:图论part04 110.字符串接龙 105.有向图的完全可达性 106.岛屿的周长(补)
任务日期:7.29 题目一链接:110. 字符串接龙 (kamacoder.com) 思路:将本题寻找附近的字符串等效于寻找四周的陆地,即寻找周围与当前字符只有一位不同的字符串,然后加入到队列中并标记上,在此基础上要将字符…...

Linux中安装MYSQL数据库
文章目录 一、MYSQL数据库介绍1.1、MySQL数据库的基本概述1.2、MySQL数据库的主要特性1.3、MySQL数据库的技术架构与组件1.4、MySQL数据库的应用与扩展性1.5、MySQL数据库的许可模式与开源生态 二、MySQL Workbench和phpMyAdmin介绍2.1、MySQL Workbench介绍2.2、phpMyAdmin介绍…...