1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-07-28 12:22:17 +08:00

Compare commits

...

7 Commits

Author SHA1 Message Date
Guide
7619f23556
Merge pull request #2507 from sevensmith/patch-1
fix some desc with dependency x
2024-10-18 16:25:52 +08:00
Guide
28ae9dc3fe [docs update]新增几个ai开源项目&typo 2024-10-18 15:48:44 +08:00
sevensmith
e36a2745fe
Update maven-core-concepts.md
fix some desc with dependency x
2024-10-18 14:58:13 +08:00
Guide
dc712a83f6
Merge pull request #2506 from whaliendev/patch-1
Correct deep-pagination-optimization.md
2024-10-17 15:12:02 +08:00
HE HUA
3c28da8047
Correct deep-pagination-optimization.md
In the section on deep pagination optimization recommendations, even with deferred joins and subqueries, the internal SQL statements will still result in deep pagination. These queries need to be rewritten to use the primary key index (id). Otherwise, there is no difference from the original SQL, and performance might even be worse.
2024-10-17 00:40:22 +08:00
Guide
82b576eb2f
Merge pull request #2505 from xieliangza/patch-1
Update java-basic-questions-01.md
2024-10-16 16:26:45 +08:00
xieliangza
eb9cd6be3b
Update java-basic-questions-01.md 2024-10-16 13:55:51 +08:00
8 changed files with 32 additions and 26 deletions

View File

@ -201,10 +201,10 @@ _玩玩电脑游戏还是必须要有 Windows 的,所以我现在是一台 Win
下面是几种常见的线程同步的方式:
1. **互斥锁(Mutex)**:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 `synchronized` 关键词和各种 `Lock` 都是这种机制。
2. **读写锁Read-Write Lock**:允许多个线程同时读取共享资源,但只有一个线程可以对共享资源进行写操作。
3. **信号量(Semaphore)**:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
4. **屏障Barrier**:屏障是一种同步原语,用于等待多个线程到达某个点再一起继续执行。当一个线程到达屏障时,它会停止执行并等待其他线程到达屏障,直到所有线程都到达屏障后,它们才会一起继续执行。比如 Java 中的 `CyclicBarrier` 是这种机制。
1. **互斥锁(Mutex)** :采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 `synchronized` 关键词和各种 `Lock` 都是这种机制。
2. **读写锁Read-Write Lock** :允许多个线程同时读取共享资源,但只有一个线程可以对共享资源进行写操作。
3. **信号量(Semaphore)** :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
4. **屏障Barrier** :屏障是一种同步原语,用于等待多个线程到达某个点再一起继续执行。当一个线程到达屏障时,它会停止执行并等待其他线程到达屏障,直到所有线程都到达屏障后,它们才会一起继续执行。比如 Java 中的 `CyclicBarrier` 是这种机制。
5. **事件(Event)** :Wait/Notify通过通知操作的方式来保持多线程同步还可以方便的实现多线程优先级的比较操作。
### PCB 是什么?包含哪些信息?
@ -238,12 +238,12 @@ PCB 主要包含下面几部分的内容:
> 下面这部分总结参考了:[《进程间通信 IPC (InterProcess Communication)》](https://www.jianshu.com/p/c1015f5ffa74) 这篇文章,推荐阅读,总结的非常不错。
1. **管道/匿名管道(Pipes)**:用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。
1. **管道/匿名管道(Pipes)** :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。
2. **有名管道(Named Pipes)** : 匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。有名管道严格遵循 **先进先出(First In First Out)** 。有名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。
3. **信号(Signal)**:信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
4. **消息队列(Message Queuing)**:消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显式地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比 FIFO 更有优势。**消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺点。**
5. **信号量(Semaphores)**:信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。
6. **共享内存(Shared memory)**:使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式。
3. **信号(Signal)** :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
4. **消息队列(Message Queuing)** :消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显式地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比 FIFO 更有优势。消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺点。
5. **信号量(Semaphores)** :信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。
6. **共享内存(Shared memory)** :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式。
7. **套接字(Sockets)** : 此方法主要用于在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。
### 进程的调度算法有哪些?

View File

@ -603,7 +603,7 @@ Node{data=23, maxLevel=1}
1. 采用**双向链表**,不同于上面的示例,存在一个回退指针。主要用于简化操作,例如删除某个元素时,还需要找到该元素的前驱节点,使用回退指针会非常方便。
2. `score` 值可以重复,如果 `score` 值一样,则按照 ele节点存储的值为 sds字典排序
3. Redis 跳跃表默认允许最大的层数是32被源码中 `ZSKIPLIST_MAXLEVEL` 定义。
3. Redis 跳跃表默认允许最大的层数是 32被源码中 `ZSKIPLIST_MAXLEVEL` 定义。
## 和其余三种数据结构的比较

View File

@ -64,12 +64,12 @@ SELECT * FROM t_order WHERE id > 100000 LIMIT 10
```sql
# 通过子查询来获取 id 的起始值,把 limit 1000000 的条件转移到子查询
SELECT * FROM t_order WHERE id >= (SELECT id FROM t_order limit 1000000, 1) LIMIT 10;
SELECT * FROM t_order WHERE id >= (SELECT id FROM t_order where id > 1000000 limit 1) LIMIT 10;
```
**工作原理**:
1. 子查询 `(SELECT id FROM t_order LIMIT 1000000, 1)` 会利用主键索引快速定位到第 1000001 条记录,并返回其 ID 值。
1. 子查询 `(SELECT id FROM t_order where id > 1000000 limit 1)` 会利用主键索引快速定位到第 1000001 条记录,并返回其 ID 值。
2. 主查询 `SELECT * FROM t_order WHERE id >= ... LIMIT 10` 将子查询返回的起始 ID 作为过滤条件,使用 `id >=` 获取从该 ID 开始的后续 10 条记录。
不过,子查询的结果会产生一张新表,会影响性能,应该尽量避免大量使用子查询。并且,这种方法只适用于 ID 是正序的。在复杂分页场景,往往需要通过过滤条件,筛选到符合条件的 ID此时的 ID 是离散且不连续的。
@ -84,12 +84,12 @@ SELECT * FROM t_order WHERE id >= (SELECT id FROM t_order limit 1000000, 1) LIMI
-- 使用 INNER JOIN 进行延迟关联
SELECT t1.*
FROM t_order t1
INNER JOIN (SELECT id FROM t_order LIMIT 1000000, 10) t2 ON t1.id = t2.id;
INNER JOIN (SELECT id FROM t_order where id > 1000000 LIMIT 10) t2 ON t1.id = t2.id;
```
**工作原理**:
1. 子查询 `(SELECT id FROM t_order LIMIT 1000000, 10)` 利用主键索引快速定位目标分页的 10 条记录的 ID。
1. 子查询 `(SELECT id FROM t_order where id > 1000000 LIMIT 10)` 利用主键索引快速定位目标分页的 10 条记录的 ID。
2. 通过 `INNER JOIN` 将子查询结果与主表 `t_order` 关联,获取完整的记录数据。
除了使用 INNER JOIN 之外,还可以使用逗号连接子查询。
@ -97,7 +97,7 @@ INNER JOIN (SELECT id FROM t_order LIMIT 1000000, 10) t2 ON t1.id = t2.id;
```sql
-- 使用逗号进行延迟关联
SELECT t1.* FROM t_order t1,
(SELECT id FROM t_order limit 1000000, 10) t2
(SELECT id FROM t_order where id > 1000000 LIMIT 10) t2
WHERE t1.id = t2.id;
```

View File

@ -120,7 +120,7 @@ ZooKeeper 主要为 Kafka 提供元数据的管理的功能。
不过,要提示一下:**如果要使用 KRaft 模式的话,建议选择较高版本的 Kafka因为这个功能还在持续完善优化中。Kafka 3.3.1 版本是第一个将 KRaftKafka Raft共识协议标记为生产就绪的版本。**
![](<https://oss.javaguide.cn/github/javaguide/high-performance/message-queue/kafka3.3.1-kraft-> production-ready.png)
![](https://oss.javaguide.cn/github/javaguide/high-performance/message-queue/kafka3.3.1-kraft-production-ready.png)
## Kafka 消费顺序、消息丢失和重复消费

View File

@ -300,7 +300,7 @@ int d = c--;
int e = --d;
```
答案:`a = 11``b = 9``c = 10` 、 `d = 10` 、 `e = 10`
答案:`a = 11``b = 9``c = 11` 、 `d = 11` 、 `e = 10`
### 移位运算符

View File

@ -379,9 +379,9 @@ public class OutterClass
}
```
**为什么内部类可以使用外部类的private属性**
**为什么内部类可以使用外部类的 private 属性**
我们在InnerClass中增加一个方法打印外部类的userName属性
我们在 InnerClass 中增加一个方法,打印外部类的 userName 属性
```java
//省略其他属性
@ -411,7 +411,7 @@ class OutterClass$InnerClass {
```
实际上在编译完成之后inner实例内部会有指向outer实例的引用`this$0`,但是简单的`outer.name`是无法访问private属性的。从反编译的结果可以看到outer中会有一个桥方法`static String access$000(OutterClass)`恰好返回String类型即userName属性。正是通过这个方法实现内部类访问外部类私有属性。所以反编译后的`printOut()`方法大致如下:
实际上在编译完成之后inner 实例内部会有指向 outer 实例的引用`this$0`,但是简单的`outer.name`是无法访问 private 属性的。从反编译的结果可以看到outer 中会有一个桥方法`static String access$000(OutterClass)`,恰好返回 String 类型,即 userName 属性。正是通过这个方法实现内部类访问外部类私有属性。所以反编译后的`printOut()`方法大致如下:
```java
public void printOut() {
@ -421,7 +421,7 @@ public void printOut() {
补充:
1. 匿名内部类、局部内部类、静态内部类也是通过桥方法来获取private属性。
1. 匿名内部类、局部内部类、静态内部类也是通过桥方法来获取 private 属性。
2. 静态内部类没有`this$0`的引用
3. 匿名内部类、局部内部类通过复制使用局部变量,该变量初始化之后就不能被修改。以下是一个案例:
@ -456,7 +456,6 @@ class OutterClass$1Inner {
```
### 条件编译
—般情况下,程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译。

View File

@ -4,11 +4,18 @@ category: 开源项目
icon: a-MachineLearning
---
由于 Java 在 AI 领域应用较少,因此相关的开源项目也非常少:
由于 Java 在 AI 领域目前的应用较少,因此相关的开源项目也非常少。
## 基础框架
- [Spring AI](https://github.com/spring-projects/spring-ai):人工智能工程应用框架,为开发 AI 应用程序提供了 Spring 友好的 API 和抽象。
- [Spring AI Alibaba](https://github.com/alibaba/spring-ai-alibaba):一款 Java 语言实现的 AI 应用开发框架,旨在简化 Java AI 应用程序开发,让 Java 开发者像使用 Spring 开发普通应用一样开发 AI 应用。
- [LangChain4j](https://github.com/langchain4j/langchain4j)LangChiain 的 Java 版本,用于简化将 LLMLarge Language Model大语言模型 集成到 Java 应用程序的过程。
- [Deeplearning4j](https://github.com/eclipse/deeplearning4j)Deeplearning4j 是第一个为 Java 和 Scala 编写的商业级,开源,分布式深度学习库。
- [Smile](https://github.com/haifengl/smile):基于 Java 和 Scala 的机器学习库。
- [GdxAI](https://github.com/libgdx/gdx-ai):完全用 Java 编写的人工智能框架,用于使用 libGDX 进行游戏开发。
- [chatgpt-java](https://github.com/Grt1228/chatgpt-java)ChatGPT Java SDK。
## 实战
- [springboot-openai-chatgpt](https://github.com/274056675/springboot-openai-chatgpt):一个基于 SpringCloud 微服务架构,已对接 GPT-3.5、GPT-4.0、百度文心一言、Midjourney 绘图等等。
- [ai-beehive](https://github.com/hncboy/ai-beehive)AI 蜂巢,基于 Java 使用 Spring Boot 3 和 JDK 17支持的功能有 ChatGPT、OpenAi Image、Midjourney、NewBing、文心一言等等。

View File

@ -197,7 +197,7 @@ Maven 在遇到这种问题的时候,会遵循 **路径最短优先** 和 **
根据路径最短优先原则X(1.0) 会被解析使用,也就是说实际用的是 1.0 版本的 X。
但是!!!这会一些问题:如果 D 依赖用到了 1.5 版本的 X 中才有的一个类,运行项目就会报`NoClassDefFoundError`错误。如果 D 依赖用到了 1.5 版本的 X 中才有的一个方法,运行项目就会报`NoSuchMethodError`错误。
但是!!!这会一些问题:如果 C 依赖用到了 1.5 版本的 X 中才有的一个类,运行项目就会报`NoClassDefFoundError`错误。如果 C 依赖用到了 1.5 版本的 X 中才有的一个方法,运行项目就会报`NoSuchMethodError`错误。
现在知道为什么你的 Maven 项目总是会报`NoClassDefFoundError``NoSuchMethodError`错误了吧?
@ -217,7 +217,7 @@ Maven 在遇到这种问题的时候,会遵循 **路径最短优先** 和 **
一般我们在解决依赖冲突的时候,都会优先保留版本较高的。这是因为大部分 jar 在升级的时候都会做到向下兼容。
如果高版本修改了低版本的一些类或者方法的话,这个时候就能直接保留高版本了,而是应该考虑优化上层依赖,比如升级上层依赖的版本。
如果高版本修改了低版本的一些类或者方法的话,这个时候就能直接保留高版本了,而是应该考虑优化上层依赖,比如升级上层依赖的版本。
还是上面的例子: