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

【JavaEE】多线程代码实例:单例模式与阻塞队列BlockingQueue

目录

单例模式:

什么是单例模式? 

单例模式的实现方式: 

饿汉模式: 

懒汉模式: 

基于并发编程对单例模式线程安全问题的讨论: 

阻塞队列:

标准库中的阻塞队列: 

自实现阻塞队列: 

生产者消费者模型: 

生产者消费者模型的实现: 

利用系统的BlockingQueue实现生产者消费者模型:

利用自实现的BlockingQueue实现生产者消费者模型:


 

单例模式:

什么是单例模式? 

单例模式能保证某个类只能存在唯一的实例,不能创建多个实例。这种设计模式是需要在特定业务场景进行使用的。

单例模式的实现方式: 

单例模式的实现方式有很多种,主要的方式是饿汉模式懒汉模式。 

饿汉模式: 

懒汉模式的简单实现:


//单例模式:饿汉模式class Singleton{//第一步实例化对象public static Singleton singleton=new Singleton();//构造方法为空private Singleton(){}//获取对象实例public static Singleton getInstance(){return  singleton;}
}public class ThreadDemo4 {public static void main(String[] args) {//Singleton singleton1=new Singleton();无法创建对象!!!//验证单一性:Singleton singleton1=Singleton.getInstance();Singleton singleton2=Singleton.getInstance();System.out.println(singleton1==singleton2);}
}

通过比较我们发现得到的实例是同一个实例,且在该模式下不能再进行实例的创建。从代码我们可以知道,该模式实例的创建要比一般类的实例创建要早,所以我们形象的称为饿汉模式(饿的等不及了),该对象的实例在类加载阶段就进行了创建。

饿汉模式如何确保创建对象是单例的?类定义时创建静态对象+私有构造方法,公开接口get实例,并且设置成静态确保可利用类名直接调用。 

懒汉模式: 

懒汉模式之所以被称为这样也是很形象的说法,这种模式下的单例模式,只有在需要实例的时候才会进行创建实例,并且只会创建这一次。

懒汉模式简单实现:


class Singleton1{public static Singleton1 singleton1=null;//先为空//同样构造方法私有化private Singleton1(){}//懒汉模式是在获取对象实例的方法中进行创建实例的public static Singleton1 getSingleton1() {if(singleton1==null){singleton1=new Singleton1();}return singleton1;}
}public class ThreadDemo5 {public static void main(String[] args) {//Singleton1 singleton1=new Singleton1();无法创建实例Singleton1 s1=Singleton1.getSingleton1();Singleton1 s2=Singleton1.getSingleton1();System.out.println(s1==s2);}
}

  

很显然,我们的实例是在第一次获取实例的时候进行创建的。 

懒汉模式是通过创建静态对象变量+需要时创建对象+提供公开的接口并且设置成静态方法,私有化构造方法实现的。

这里需要注意:上述的单例模式在单线程的模式下运行时没有安全问题的,但是放到并发编程中就会出现问题!!!

基于并发编程对单例模式线程安全问题的讨论: 

 我们可以看到:在饿汉模式下,我们一上来就把对象实例化了,在多线程当中只会有读的操作,所以不会出现线程安全问题,所以我们说饿汉模式下的单例模式是线程安全的。但是对于懒汉模式而言,在获取实例的时候创建了实例,这样就即涉及到读,又涉及到写的操作了。

线程安全问题发生在首次创建实例时. 如果在多个线程中同时调用 getInstance 方法, 就可能导致
创建出多个实例.一旦实例已经创建好了, 后面再多线程环境调用 getInstance 就不再有线程安全问题了(不再修改singleton1 了)

所以使用synchronized可以改善这里的线程安全问题

懒汉模式多线程改进1.0版本:


class Singleton1{public static Singleton1 singleton1=null;//先为空//同样构造方法私有化private Singleton1(){}//懒汉模式是在获取对象实例的方法中进行创建实例的public synchronized static Singleton1 getSingleton1() {if(singleton1==null){singleton1=new Singleton1();}return singleton1;}
}

但是,你以为这样就结束了吗?NO!!!

这里面还有一些问题!比如锁竞争,内存可见性问题等等。加锁 / 解锁是一件开销比较高的事情。 而懒汉模式的线程不安全只是发生在首次创建实例的时候。因此后续使用的时候, 不必再进行加锁了。所以我们考虑使用一个if判定下看当前是否已经把singleton1实例创建出来了。同时为了避免 "内存可见性" 导致读取的singleton1出现偏差, 于是补充上volatile。当多线程首次调用getInstance, 大家可能都发现instance为null, 于是又继续往下执行来竞争锁,其中竞争成功的线程, 再完成创建实例的操作。当这个实例创建完了之后, 我们还需要用一个if来判断是否创建完毕了,如果创建完毕了,其他竞争到锁的线程就被该层的if 挡住,也就不会继续创建其他实例。

所以我们将对懒汉模式进行二次改进:

懒汉模式多线程改进2.0版本:


class Singleton1{public volatile static Singleton1 singleton1=null;//先为空//同样构造方法私有化private Singleton1(){}//懒汉模式是在获取对象实例的方法中进行创建实例的public  static Singleton1 getSingleton1() {if(singleton1==null){synchronized (Singleton1.class){if(singleton1==null){singleton1=new Singleton1();}}}return singleton1;}
}

这样我们的懒汉模式才算是完善了。

以下代码在加锁的基础上, 做出了进一步改动:
使用双重 if 判定, 降低锁竞争的频率,给singleton1加上了 volatile
我们举个例子

1) 有三个线程, 开始执行getInstance, 通过外层的if (singleton1 == null) 知道了实例还没有创建的消息,于是开始竞争同一把锁
2) 其中线程1率先获取到锁, 此时线程1通过里层的if (singleton1 == null) 进一步确认实例是否已经创建,如果没创建, 就把这个实例创建出来
3) 当线程1释放锁之后, 线程2和线程3也拿到锁, 也通过里层的 if (singleton1 == null) 来确认实例是否已经创建, 发现实例已经创建出来了, 就不再创建了
4) 后续的线程, 不必加锁, 直接就通过外层if (singleton1 == null) 就知道实例已经创建了, 从而不再尝试获取锁了,降低了开销
试着理解一下吧。

阻塞队列:

阻塞队列是一种特殊的队列,也遵守 "先进先出" 的原则。
阻塞队列能是一种线程安全的数据结构, 并且具有以下特性:
当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素。
当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插入元素。

阻塞队列的一个典型应用场景就是 "生产者消费者模型". 这是一种非常典型的开发模型 

标准库中的阻塞队列: 

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

标准库中提供了实现阻塞队列功能的类和接口。虽然说,阻塞队列本质上还是一个队列,也就是说实现了Queue接口,也有普通队列方法,但是我们使用阻塞队列主要使用的不是这些,而是它特有的阻塞功能,此时对应的入队和出队操作的方法分别对应的是put和take方法


同时BlockingQueue还有这些比较常用的实现Queue接口的类,背后的数据结构看名字就知道是什么了。此外,后面是Deque的是双端阻塞队列。 

注意点:

BlockingQueue 是一个接口, 真正实现的类是 LinkedBlockingQueue。
put 方法用于阻塞式的入队列, take 用于阻塞式的出队列。
BlockingQueue也有offer, poll, peek 等方法, 但是这些方法不带有阻塞特性。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;public class BlockingQueueDemo1 {public static void main(String[] args) throws InterruptedException {//阻塞队列BlockingQueue<String> queue=new LinkedBlockingQueue<>();//入队列queue.put("abc");//出队列,如果没有就进行阻塞String elem=queue.take();System.out.println(elem);}
}

在阻塞队列中,如果队列放满了或者没有出的元素都会进入阻塞状态。这里演示一下没有元素的情况:

 此时队列中没有元素,程序进行了阻塞。

自实现阻塞队列: 

 实现阻塞队列的关键在于实现其阻塞的功能。其他的和普通的队列差不多。这里主要实现put和take方法:


class MyBlockingQueue{//利用数组实现private int[] arr=new int[1000];//设定数组长度为1000private int size=0;//记录数组的内容长度//利用end和begin两个指针使得数组变为循环数组(逻辑上的循环)private int end=0;private int begin=0;//实现put方法//阻塞考虑使用wait和notify进行唤醒(sleep不太靠谱)public void put(int value) throws InterruptedException {//判断是否满了(这里要用循环判断,因为在多线程当中,线程被唤醒的时候不一定不满)//加锁保证原子性synchronized (this){while(size>= arr.length){this.wait();}//不满之后放入元素arr[end]=value;//调整长度end++;size++;//如果放满了则将end变为0if(end>= arr.length){end=0;}//进行唤醒this.notify();}}//实现take方法public int take() throws InterruptedException {synchronized (this){//判断是否为空while (size==0){this.wait();}//不空之后开始取出元素int ret=arr[begin];begin++;if(begin>= arr.length){begin=0;}size--;this.notify();return ret;}}//长度public synchronized int Size(){return size;}}public class BlockingQueueDemo3 {public static void main(String[] args) throws InterruptedException {MyBlockingQueue queue=new MyBlockingQueue();queue.put(100);queue.put(200);queue.put(300);System.out.println(queue.take());System.out.println(queue.take());System.out.println(queue.take());}
}

 

 显然,当其中没有元素的时候就会阻塞等待。 

生产者消费者模型: 

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。
生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取。

首先,阻塞队列相当于一个缓冲区,它平衡了生产者和消费者之间的处理能力。

其次,阻塞队列使得生产者和消费者之间的进行了解耦合,也就是消费者不再是直接依赖生产者。

对于阻塞队列,生产者是添加元素的一方,消费者是取元素的一方,产品是阻塞队列的元素。生产者和消费者通过阻塞队列相互联系。

画个图演示一下:

我们举向游戏里面氪金的例子吧!!!

这样就会出现一个问题:服务器A和服务器B的耦合太高,一旦其中一个服务器出现了问题,就会导致另一个服务器也无法完成需求。就会出现一个服务器挂了,把另一个服务器也带走的情况。

并且,如果我们需要在此基础上加一个新的服务器参与其他相关的功能,比如日志,也是会有问题的!

那么如何解决这种情况呢?这就用到了当前的生产者消费者模型。生产者生成的资源,我们可以将其放到一个阻塞队列当中去,当有消费者需要消费的时候,就直接从该阻塞队列当中去取,如果队列中没有资源,就阻塞等待,等待生产者进行生产,当阻塞队列满的时候,生产者也要进行阻塞等待。这里的服务器A就是生产者,服务器BC就是消费者。所以我们可以利用该模型进行这样的设计:

生产者消费者模型的实现: 

利用系统的BlockingQueue实现生产者消费者模型:

首先我们利用系统提供的BlockingQueue实现生产者消费者模型: 

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;public class BlockingQueueDemo2 {public static void main(String[] args) {//创建阻塞队列BlockingQueue<Integer>queue=new LinkedBlockingQueue<>();//使用两个线程:一个线程充当生产者,一个线程充当消费者//生产者Thread t1=new Thread(()->{int count=0;while(true){try {queue.put(count);System.out.println("生产者生产:"+count);count++;Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t2=new Thread(()->{while(true){try {int ret=queue.take();System.out.println("消费者消费:"+ret);Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t1.start();t2.start();}
}

 

我们可以明确的看到,消费元素和生产元素是成对出现的。这就不会出现生产者没有生产出来的东西被消费的情况。 

利用自实现的BlockingQueue实现生产者消费者模型:


class MyBlockingQueue1{//利用数组实现private int[] arr=new int[1000];//设定数组长度为1000private int size=0;//记录数组的内容长度//利用end和begin两个指针使得数组变为循环数组(逻辑上的循环)private int end=0;private int begin=0;//实现put方法//阻塞考虑使用wait和notify进行唤醒(sleep不太靠谱)public void put(int value) throws InterruptedException {//判断是否满了(这里要用循环判断,因为在多线程当中,线程被唤醒的时候不一定不满)//加锁保证原子性synchronized (this){while(size>= arr.length){this.wait();}//不满之后放入元素arr[end]=value;//调整长度end++;size++;//如果放满了则将end变为0if(end>= arr.length){end=0;}//进行唤醒this.notify();}}//实现take方法public int take() throws InterruptedException {synchronized (this){//判断是否为空while (size==0){this.wait();}//不空之后开始取出元素int ret=arr[begin];begin++;if(begin>= arr.length){begin=0;}size--;this.notify();return ret;}}//长度public synchronized int Size(){return size;}}public class BlockingQueueDemo4 {public static void main(String[] args) throws InterruptedException {MyBlockingQueue1 queue1=new MyBlockingQueue1();//生产者Thread producer =new Thread(()->{int count=0;while(true){try {queue1.put(count);System.out.println("生产者生产元素:"+count);count++;Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//消费者Thread customer =new Thread(()->{while(true){try {int ret=queue1.take();System.out.println("消费者消费元素:"+ret);Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}}});producer.start();customer.start();}
}

相关文章:

【JavaEE】多线程代码实例:单例模式与阻塞队列BlockingQueue

目录 单例模式&#xff1a; 什么是单例模式&#xff1f; 单例模式的实现方式&#xff1a; 饿汉模式&#xff1a; 懒汉模式&#xff1a; 基于并发编程对单例模式线程安全问题的讨论&#xff1a; 阻塞队列&#xff1a; 标准库中的阻塞队列&#xff1a; 自实现阻塞…...

算法思想 - 搜索算法

本文主要介绍算法中搜索算法的思想&#xff0c;主要包含BFS&#xff0c;DFS。搜索相关题目深度优先搜索和广度优先搜索广泛运用于树和图中&#xff0c;但是它们的应用远远不止如此。BFS广度优先搜索的搜索过程有点像一层一层地进行遍历&#xff0c;每层遍历都以上一层遍历的结果…...

C#底层库--日期扩展类(上周、本周、明年、前年等)

系列文章 C#底层库–记录日志帮助类 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/124187709 C#底层库–数据库访问帮助类&#xff08;MySQL版&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/126886379 …...

如何在 Webpack 中开启图片压缩

工具对比 npmtrends.com/image-minim… 这四个压缩工具&#xff0c;从下载量来看&#xff0c;image-webpack-loader 较多&#xff0c;image-minimizer-webpack-plugin、imagemin-webpack-plugin 次之&#xff0c;imagemin-webpack 已经不再维护&#xff0c;因此不考虑此工具。 …...

Web-Filter

## 今日内容 1. Filter&#xff1a;过滤器 2. Listener&#xff1a;监听器 # Filter&#xff1a;过滤器 1. 概念&#xff1a; * 生活中的过滤器&#xff1a;净水器,空气净化器&#xff0c;土匪、 * web中的过滤器&#xff1a;当访问服务器的资源时…...

测试写文章自动保存

近日恰逢双十一,瞅了瞅自己干瘪的钱包,没忍心入手期待已久的 macPro,只好在虚拟机里玩一下 mac好了,等以后钱包傲气的时候再来个真实的。 安装环境: windows10 VMWare14.2 2018-7-28 小嘚瑟补充:唧唧歪歪大半年,一夜回到解放前,终于剁手整了个真机,可以折腾一下了 ——…...

云平台搭建实例

嗨嗨&#xff0c;每天一更是不是很奈斯&#xff1f;我也觉得&#xff0c;昨天晚上我学校的老师借一天一千的设备&#xff0c;只能用七天&#xff0c;所以我拿出来给你们没有设备和刚用设备的看看吧。操作&#xff1a;首先我们将云平台安装好后&#xff0c;插上网线&#xff0c;…...

【Airplay_BCT】关于Bonjour的概念解答

1.什么是Bonjour&#xff1f; Bonjour&#xff0c;也称为零配置网络&#xff0c;可以自动发现 IP 网络上的计算机、设备和服务。 Bonjour 使用行业标准 IP 协议&#xff0c;允许设备自动发现彼此&#xff0c;无需输入 IP 地址或配置 DNS 服务器。具体来说&#xff0c;Bonjour …...

C++深入浅出(九)—— 多态

文章目录1. 多态的概念2. 多态的定义及实现&#x1f351; 多态的构成条件&#x1f351; 虚函数&#x1f351; 虚函数的重写&#x1f351; 虚函数重写的两个例外&#x1f351; C11的override 和 final&#x1f351; 重载、覆盖(重写)、隐藏(重定义)的对比3. 抽象类&#x1f351;…...

shell学习4

目录 一、统计文本中的词频 二、压缩javascript 三、打印文件的或行中的第n个单词或列---awk 3.1 利用awk打印文件中每行中的第五个单词。 3.2 利用awk打印当前目录下的文件的权限和文件名 3.3 利用awk打印从M行到N行这个范围内的所有文本 3.4 利用awk 部分提取文件中的内…...

VR全景行业的应用价值如何呈现?

互联网高速发展的今天&#xff0c;多媒体所包含的种类也是越来越多&#xff0c;而一些较为传统的表现方式已经越来越无法满足大部分客户对展示方式的要求。而在传统的表现方式中&#xff0c;展现的方式无非是静态的平面图片以及动态的视频&#xff0c;但是他们都有一个缺点就是…...

ESP-IDF:TCP多线程并发服务器

核心代码&#xff1a; 核心思想就是主线程只处理socket监听功能&#xff0c;把数据处理部分分配到不同的线程中去处理。来了一个客户端连接&#xff0c;就分配新的线程去处理该客户端的数据请求。 代码&#xff1a; /多线程并发服务器/ #include <stdio.h> #include …...

Springboot扩展点之SmartInitializingSingleton

前言这篇文章会重点分析一下SmartInitializingSingleton扩展点的功能 特性、实现方式 、工作原理。SmartInitializingSingleton扩展点内只有一个扩展方法&#xff0c;且执行时机在Spring Bean的生命周期里比较靠后&#xff0c;很重要&#xff0c;但是也很简单。功能特性1、Smar…...

基于linux内核的驱动开发学习

1 驱动 定义&#xff1a;驱使硬件动起来的程序 种类&#xff1a;裸机驱动&#xff1a;需求分析--》查原理图--》查芯片手册--》code 系统驱动&#xff1a;需求分析--》查原理图--》查芯片手册--》设备树--》code --》安装到内核中…...

python3 django gunicorn

首先&#xff0c;Gunicorn是一个高效的Web服务器&#xff0c;地位相当于Java中的Tomcat。简单来说gunicorn封装了HTTP的底层实现&#xff0c;我们通过gunicorn启动服务&#xff0c;用户请求与服务相应都经过gunicorn传输。下载gunicorn的方法也比较简单&#xff0c;在django工程…...

专家分享 | 租赁型售楼处标准化示范区提效研究

2023年2月8日上午&#xff0c;优积科技邀请原金地集团北京公司 高级室内设计专业应锎经理为我司团队分享《租赁型售楼处标准化示范区提效》的专题。 此次专家分享课题加上大家踊跃讨论时间长达3小时&#xff0c;会上应总详细介绍了租赁型售楼处标准化示范区提效&#xff0c;需…...

linux之echo使用技巧

参考文章&#xff1a;linux基本功系列-echo命令实战一、echo 命令是什么&#xff1f;作用&#xff1a; echo命令能将指定文本显示在Linux命令行上&#xff0c;或者通过重定向符写入到指定的文件中。语 法&#xff1a;echo [-ne][字符串] / echo [–help][–version]补充说明&am…...

Keras实例教程(7)之构建模型的第三种方式

多年以前,在TensorFlow中搭建深度学习模型对于很多人来说其实仍然是比较困难的。相比之下,Keras作为独立于TensorFlow的一种深度学习框架则要简单很多。在TensorFlow与PyTorch的竞争中逐渐式微的情况下,TensorFlow团队终于宣布Keras将成为在tensorflow2.0中构建和训练模型的…...

【JUC并发编程】18 CopyOnWriteArrayList源码也就够看2分钟

文章目录1、CopyOnWriteArrayList概述2、原理 / 源码1&#xff09;构造函数2、add()3&#xff09;get()4&#xff09;remove()5&#xff09;iterator()1、CopyOnWriteArrayList概述 CopyOnWriteArrayList相当于线程安全的ArrayList&#xff0c;底层是一个可变数组。 特点如下…...

如何优雅的实现回调函数?

本篇文章又是一期优雅的代码编程介绍———回调函数。 传统的nodejs编程都是这样的 const fs require(fs) fs.readFile(test.txt,utf8, function(err, dataStr){if(err){} }) 嵌套层级如果多了就成回调地狱了。如果我们将这种风格的代码转换成这样呢&#xff1f; const fs …...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...