Title: Large-scale Data Augmentation for Emotional Support Conversation with Pre-trained Language Models
--- -研究开放式对话数据增强,采用大语言模型 GPT-3 拓展了 ESConv 数据集大小
-
论文速览
-Abstract
--
-
- 利用LLM进行数据增强,使用公开的对话帖子触发各种主题的对话 -
Introduction
--
-
- 目前工作的缺陷
-
-
-
- 成本高、耗时长 -
- 预算限制,所收集的对话规模小,主题少 -
- - 本文主要贡献
-
-
-
- 关键发现 -
- 使用 GPT-J 和公开对话帖子触发各种主题的对话 -
- 构建机器增强数据集AUGES,具有更广泛和多样化的主题覆盖范围,可以提供更有效的情感支持 -
-
Related Work
--
-
- 预训练模型 -
- 预训练模型的数据增强 -
Key Findings
--
-
- 语言模型优于对话模型
-
-
-
- 语言模型存储了从大规模训练语料库中学习到的更丰富的知识,有助于更好地泛化到各种对话主题 -
- 与会话模型 BlenderBot 相比,gpt生成的对话具有更好的对话连贯性和一致性 -
- - 语言模型比交互式仿真更适合开放式对话数据增强 -
- 提示GPT不如微调GPT模型
-
-
-
- 提示型GPT-3生成可控性差 -
- 只有微调才能掌握任务场景和所需特征 -
- - 少样本(Few-shot)微调导致更好的泛化和更高的多样性
-
-
-
- 保持语言模型的内在知识 -
- 增加调优样本或训练步骤会导致对域外主题的泛化能力差 -
- 在大规模自动数据增强的帮助下,训练对话模型可能只需要少量手动策划的对话样本 -
- - 信息性查询(第一个对话帖子)是触发主题对话的必要条件
-
-
-
- 泛型和无信息的查询往往导致离题和肤浅的对话 -
-
Methodology
--
-
- 主干模型:GPT-3,微调后的GPT-J -
- 提示模板:对话场景+情感支持 -
- 将第一个对话框作为触发查询,模型生成后续的对话 -
- 不采用Prompt提示,使用ESConv微调GPT-J -
- 触发Query
-
-
-
- 数据来源:EmpatheticDialogues(移情对话数据集)Reddit(心理健康相关的帖子) -
- 保留带有负面情绪的Query -
- - 过滤结果,删除非法对话 -
AUGESC
-相比ESConv对话轮次更少,内容更长。语料库规模的扩大导致唯一二元分词的数量
--
-
- ESConv中的对话话题与数据收集时期(如covid, pandemic, christmas)密切相关 -
- AUGESC-ED 涵盖了更多关于日常生活的主题(例如,汽车、狗、房子、邻居) -
- AUGESC-Reddit 涵盖了关于心理健康的主题(例如,抑郁、焦虑、治疗师) -
Quality Evaluation
-在信息一致性、话题一致性和对话基础等方面存在问题
-Interactive Evaluation
---AUGESC是对ESConv的一种补充,用AUGESC+ESConv训练出来的模型表现优于只使用ESConv的模型
-
Conclusion
-AUGESC能够显著增强对话模型提供情感支持的能力
+Title: Large-scale Data Augmentation for Emotional +Support Conversation with Pre-trained Language Models
+++ +研究开放式对话数据增强,采用大语言模型 GPT-3 拓展了 ESConv +数据集大小
+
论文速览
+Abstract
+-
+
- 利用LLM进行数据增强,使用公开的对话帖子触发各种主题的对话 +
Introduction
+-
+
目前工作的缺陷
+-
+
- 成本高、耗时长 +
- 预算限制,所收集的对话规模小,主题少 +
+本文主要贡献
+-
+
- 关键发现 +
- 使用 GPT-J 和公开对话帖子触发各种主题的对话 +
- 构建机器增强数据集AUGES,具有更广泛和多样化的主题覆盖范围,可以提供更有效的情感支持 +## Related Work +
+预训练模型
+预训练模型的数据增强 ## Key Findings
+语言模型优于对话模型
+-
+
- 语言模型存储了从大规模训练语料库中学习到的更丰富的知识,有助于更好地泛化到各种对话主题 +
- 与会话模型 BlenderBot +相比,gpt生成的对话具有更好的对话连贯性和一致性 +
+语言模型比交互式仿真更适合开放式对话数据增强
+提示GPT不如微调GPT模型
+-
+
- 提示型GPT-3生成可控性差 +
- 只有微调才能掌握任务场景和所需特征 +
+少样本(Few-shot)微调导致更好的泛化和更高的多样性
+-
+
- 保持语言模型的内在知识 +
- 增加调优样本或训练步骤会导致对域外主题的泛化能力差 +
- 在大规模自动数据增强的帮助下,训练对话模型可能只需要少量手动策划的对话样本 +
+信息性查询(第一个对话帖子)是触发主题对话的必要条件
+-
+
- 泛型和无信息的查询往往导致离题和肤浅的对话 ## Methodology +
+主干模型:GPT-3,微调后的GPT-J
+提示模板:对话场景+情感支持
+将第一个对话框作为触发查询,模型生成后续的对话
+不采用Prompt提示,使用ESConv微调GPT-J
+触发Query
+-
+
- 数据来源:EmpatheticDialogues(移情对话数据集)Reddit(心理健康相关的帖子) +
- 保留带有负面情绪的Query +
+过滤结果,删除非法对话 ## AUGESC +相比ESConv对话轮次更少,内容更长。语料库规模的扩大导致唯一二元分词的数量
+ESConv中的对话话题与数据收集时期(如covid, pandemic, +christmas)密切相关
+AUGESC-ED +涵盖了更多关于日常生活的主题(例如,汽车、狗、房子、邻居)
+AUGESC-Reddit 涵盖了关于心理健康的主题(例如,抑郁、焦虑、治疗师) +## Quality Evaluation 在信息一致性、话题一致性和对话基础等方面存在问题 +## Interactive Evaluation > +AUGESC是对ESConv的一种补充,用AUGESC+ESConv训练出来的模型表现优于只使用ESConv的模型
+
Conclusion
+AUGESC能够显著增强对话模型提供情感支持的能力
Conclus
-
+
+
diff --git a/2023/Control Globally, Understand Locally/index.html b/2023/Control Globally, Understand Locally/index.html
index 7967a97..b52020c 100644
--- a/2023/Control Globally, Understand Locally/index.html
+++ b/2023/Control Globally, Understand Locally/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -153,7 +153,7 @@
-
+
@@ -266,134 +266,104 @@
- Title: Control Globally, Understand Locally. A Global-to-Local Hierarchical Graph Network for Emotional Support Conversation.
-创新点:
-
-- 在 Encoder 和 Decoder 之间加了一层 GCNConv 和 RGCNConv
-
-
-
- 论文速览
- Abstract
-
-- 目前研究的缺陷
-
-- 关注序列上下文信息,忽略了全局原因和局部心理意图与其的层次关系
-
-
-- 本文
-
-- 提出了一个全局到局部的层次图网络来捕获多源信息(全局原因、局部意图和对话历史)并建模它们之间的层次关系,该网络由一个多源编码器、一个层次图推理器和一个全局引导解码器组成
-- 设计了一个新的训练目标来监测全局的语义信息
-
-
-
- Introduction
-
-- 探索求助者情绪问题的原因:全局地控制情感支持对话的整个流程
-- 了解求助者的心理意图:帮助系统局部了解求助者当前时的心理状态
-- 本文目标
-
-- 捕获全局原因和局部心理意图
-- 建模全局与局部之间的关系
-
-
-- 解决方法【全局到局部层次图网络GLHG】
-
-- 多源编码器:COMET提取局部心理意图
-- 层次图推理机:全局原因(对话级)、局部心理意图(句子级)和对话历史之间的层次关系进行建模
-- 解码器中设计了一个新的训练目标来监控全局原因的语义信息
-
-
-
- Related Work
-
-- 图建模对话
-
-- GCN 利用自我和对话者间依赖性来模拟会话上下文
-- EGAE 使用图网络捕获面向任务对话中的对话模式
-
-
-- 常识性知识
-
-- 与本人有关的心理状态:xReact、xIntent
-
-
-
- Approach
-
-- 问题定义
-- 多源编码器
-
-- BlenderBot Encoder + Max-pooling
-- 上下文 + 全局原因 + 局部原因
-
-
-- 分层图推理机
-
-- GAT 图注意力网络:其他邻域信息的特征传播到当前节点,具有确定节点之间重要性和相关性的优点
--
-
注意力函数(2017出版)
-
--
-
注意力机制
-
--
-
-
--
-
注意力机制
-
--
-
-
-
-
-- Global-guide 解码器
-
-- 响应生成
-
--
-
,v表示图神经网络得到的全局变量
-
-
-
-- 监督全局语义信息:预测问题类型
-
--
-
-
-
-
-
-
-- 联合训练
-
-- 对数似然损失+交叉熵损失
--
-
![img]()
-
-
-
-
- Experiments
-
-- 指标:plexity (PPL), BLEU-n (B-n), ROUGE-L (R-L), Distinct-1(D-1), and Distinct-2 (D-2)
-- 由于有了意图特征,提出建议更具体有效
-
- Conclusion
-
-- 全局到局部的层次图网络(Global-to-Local Hierarchical Graph network, GLHG)来捕获多源信息并从全局到局部的角度建模层次关系
-- 新的训练目标“预测Seeker遇到问题的类型”
-
- 关注的问题 / 本文的优势
- 解决方法 / 创新点
-
-- 多源编码器利用情境信息并将心理意图与COMET结合,捕获全局原因和局部意图
-- 分层图推理机在全局原因、局部心理意图和对话历史之间进行交互,建模不同层次的关系(hierarchical graph reasoner)
-
- 实验结论
- 有待提升的部分
+ Title: Control Globally, Understand Locally. A
+Global-to-Local Hierarchical Graph Network for Emotional Support
+Conversation.
+创新点:
+
+- 在 Encoder 和 Decoder 之间加了一层 GCNConv 和 RGCNConv
+
+
+
+论文速览
+Abstract
+
+目前研究的缺陷
+
+- 关注序列上下文信息,忽略了全局原因和局部心理意图与其的层次关系
+
+本文
+
+- 提出了一个全局到局部的层次图网络来捕获多源信息(全局原因、局部意图和对话历史)并建模它们之间的层次关系,该网络由一个多源编码器、一个层次图推理器和一个全局引导解码器组成
+- 设计了一个新的训练目标来监测全局的语义信息 ## Introduction
+
+探索求助者情绪问题的原因:全局地控制情感支持对话的整个流程
+了解求助者的心理意图:帮助系统局部了解求助者当前时的心理状态
+本文目标
+
+- 捕获全局原因和局部心理意图
+- 建模全局与局部之间的关系
+
+解决方法【全局到局部层次图网络GLHG】
+
+- 多源编码器:COMET提取局部心理意图
+- 层次图推理机:全局原因(对话级)、局部心理意图(句子级)和对话历史之间的层次关系进行建模
+- 解码器中设计了一个新的训练目标来监控全局原因的语义信息 ## Related
+Work
+
+图建模对话
+
+- GCN 利用自我和对话者间依赖性来模拟会话上下文
+- EGAE 使用图网络捕获面向任务对话中的对话模式
+
+常识性知识
+
+- 与本人有关的心理状态:xReact、xIntent ## Approach
+
+问题定义
+多源编码器
+
+- BlenderBot Encoder + Max-pooling
+- 上下文 + 全局原因 + 局部原因
+
+分层图推理机
+
+- GAT
+图注意力网络:其他邻域信息的特征传播到当前节点,具有确定节点之间重要性和相关性的优点
+
+注意力函数(2017出版)
+
+
+注意力机制
+![img]()
+
+注意力机制
+![img]()
+
+Global-guide 解码器
+
+- 响应生成
+
+
+,v表示图神经网络得到的全局变量
+
+- 监督全局语义信息:预测问题类型
+
+![img]()
+
+
+联合训练
+
+- 对数似然损失+交叉熵损失
+
+
+Experiments
+
+指标:plexity (PPL), BLEU-n (B-n), ROUGE-L (R-L),
+Distinct-1(D-1), and Distinct-2 (D-2)
+由于有了意图特征,提出建议更具体有效 ## Conclusion
+全局到局部的层次图网络(Global-to-Local Hierarchical Graph
+network, GLHG)来捕获多源信息并从全局到局部的角度建模层次关系
+新的训练目标“预测Seeker遇到问题的类型” # 关注的问题 /
+本文的优势
+
+解决方法 / 创新点
+
+- 多源编码器利用情境信息并将心理意图与COMET结合,捕获全局原因和局部意图
+- 分层图推理机在全局原因、局部心理意图和对话历史之间进行交互,建模不同层次的关系(hierarchical
+graph reasoner) # 实验结论
+
+有待提升的部分
@@ -482,7 +452,8 @@ true
+
+
diff --git a/2023/DQ-HGAN/index.html b/2023/DQ-HGAN/index.html
index dc6d419..5c1a3d6 100644
--- a/2023/DQ-HGAN/index.html
+++ b/2023/DQ-HGAN/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,7 @@
-
+
@@ -260,144 +260,124 @@
- Title: A heterogeneous graph attention network based deep Q-learning for emotional support conversation generation
-
- 论文速览
- Abstract
-
-- 关注的问题
-
-- 动态建模对用户状态,包含个体的意图和情感
-- 综合各类因素选择最合适的支持策略
-
-
-- 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
-
-- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络
-- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法
-
-
-
- Introduction
-
-- 目前研究
-
-- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。
-
-
-- 关注的问题
-
-- 建模用户状态
-- 选择最优策略,以产生有效的保障响应
-
-
-- 提出的方法
-
-- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边
-- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达
-- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。
-
-
-- 主要贡献
-
-- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化
-- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态
-- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应
-- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应
-
-
-
- Related Work
-
-- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
-
-- 多头注意力机制
-
-- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力
-- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差
-
-
-- 词典
-
-- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义
-
-
-
-
-- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
-
-- 同构图【忽略了用户意图和情感的异构性】
-
-- GAT 图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互
-- GCN 图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖
-
-
-- 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。
-
-
-- 策略选择
-
-- 基于规则或启发式方法
-- 强化学习方法(如:Q-learning)
-
-- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应
-
-
-
-
-- 响应生成
-
-- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略
-
-
-
- Preliminaries
-
-- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中
-- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性
-- ATOMIC:得到意图或目的(xIntent)
-- NRC VAD 词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance)
-- 问题定义:上下文+策略+Query =>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
-
- Method
-
- 多源编码器
-
-
--
-
transformer编码器(TransformerEncoder)
-
-- ht = TransformerEncoder(Ht)
-
-
--
-
意图词典(COMET):通过对ATOMIC 微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
-
--
-
gt=TransformerEncoder(wi∈F∑softmax(ciTht)ci)
-
-
-
--
-
情感分类器(NRC VAD词典)
-
--
-
et=TransformerEncoder(wk∈Z∑softmax(zkTht)gt)
-
-
-
-
- 基于异构图的用户状态跟踪![img]()
- DQN强化学习![img]()
- 响应生成解码器![img]()
- Experiments
-Conclusion
- 关注的问题 / 本文的优势
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
+ Title: A heterogeneous graph attention network based
+deep Q-learning for emotional support conversation generation
+
+论文速览
+Abstract
+
+- 关注的问题
+
+- 动态建模对用户状态,包含个体的意图和情感
+- 综合各类因素选择最合适的支持策略
+
+- 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
+
+- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络
+- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法
+## Introduction
+
+- 目前研究
+
+- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。
+
+- 关注的问题
+
+- 建模用户状态
+- 选择最优策略,以产生有效的保障响应
+
+- 提出的方法
+
+- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边
+- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达
+- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。
+
+- 主要贡献
+
+- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化
+- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态
+- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应
+- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep
+Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应
+## Related Work
+
+- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
+
+- 多头注意力机制
+
+- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力
+- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差
+
+- 词典
+
+- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义
+
+
+- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
+
+- 同构图【忽略了用户意图和情感的异构性】
+
+- GAT
+图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互
+- GCN
+图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖
+
+- 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。
+
+- 策略选择
+
+- 基于规则或启发式方法
+- 强化学习方法(如:Q-learning)
+
+- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应
+
+
+- 响应生成
+
+- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略
+## Preliminaries
+
+- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中
+- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性
+- ATOMIC:得到意图或目的(xIntent)
+- NRC VAD
+词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance)
+- 问题定义:上下文+策略+Query
+=>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
+## Method
![88c61f5be72a795a087441904fcd0ad9_3_Figure_2_780332990.png]()
+
+多源编码器
+
+
+- transformer编码器(TransformerEncoder)
+
+- ht = TransformerEncoder(Ht)
+
+- 意图词典(COMET):通过对ATOMIC
+微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
+
+- \[g_{t}=TransformerEncoder\left(\sum_{w_{i}\in\mathscr{F}}\operatorname{softmax}\left(c_{i}^{T}
+h_{t}\right)c_{i}\right) \]
+
+- 情感分类器(NRC VAD词典)
+
+- \[e_{t}=\text{TransformerEncoder}\left(\sum_{w_{k}
+\in \mathscr{Z}}\operatorname{softmax}\left(z_{k}^{T} h_{t}\right)
+g_{t}\right) \text { }\]
+
+
+基于异构图的用户状态跟踪![img]()
+DQN强化学习![img]()
+响应生成解码器![img]()
+Experiments
+Conclusion
+关注的问题 / 本文的优势
+解决方法 / 创新点
+实验结论
+有待提升的部分
@@ -486,7 +466,8 @@ true
+
+
diff --git a/2023/FADO/index.html b/2023/FADO/index.html
index 5d957f8..bcc1fa7 100644
--- a/2023/FADO/index.html
+++ b/2023/FADO/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,147 +255,146 @@
- Title: Feedback-Aware Double COntrolling Network for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 双层反馈策略选择器:通过反馈信息预测策略
-- 双层控制阅读器:通过策略约束上下文响应
-- 策略词典:丰富策略的语义信息
-
- Introduction
- Related Work
- Problem Formulation
- Approach
-
-- 上下文编码器
-
-- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
-
-
-- 双层反馈策略选择器
-
-- 策略选择
-
-- 输入
-
-- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
-- BlenderBot Encoder 编码策略S
-- EmoBERTa Encoder 编码上下文对话U
-
-
-- 公式
-
-- 上下文编码器(策略S同理):$$\boldsymbol{H}=\operatorname{Enc}{cxt}\left(\boldsymbol{[CLS]}, \boldsymbol{u}{1}, \boldsymbol{[SEP]}, \boldsymbol{u}{2}, …, \boldsymbol{u}{M}\right)$$,M为对话数
-
--
-\boldsymbol{H}=\left(\boldsymbol{u}_{1},..., \boldsymbol{u}_{T}\right)$$,T为Token数
-
-
--
-\boldsymbol{E}=\left(\boldsymbol{e}_{1},..., \boldsymbol{e}_{T}\right)$$,T为Token数
-
-
-- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
-
-
-
-
-
-
-- 双层反馈
-
-- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
-- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
-- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr + uΔc【计算损失时,给予正向或负向的反馈】
-
-
-
-
-- 双控读取器(模仿情感聊天机器ECM)
-
-- context-to-strategy:利用上下文信息来选择上下文相关的策略
-
--
-\boldsymbol{g}^{c} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
-
--
-\boldsymbol{g}^{o} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- 残差连接:在原始信息和更新信息之间进行权衡
-
--
-\begin{array}{r}
-
-
-
-h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
-\end{array}$$
-
-
-- 策略字典
-
-- 输入策略令牌的描述, 而不是策略令牌,以便模型对策略进行更深入的理解
-- Encoder-Decoder 之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
-- 响应生成
-
-- BlenderBot Decoder:$$\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}{<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}{y<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)$$
-
-
-- 联合训练
-
-- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
-
--
-\mathcal{L}_{1}=\left\{\begin{array}{ccc}
-
-
-
--\hat{o} \log \left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right) & \text { if } & \Delta s \leq 0
-\end{array}\right.\$$
-- 响应生成:标准交叉熵损失优化 cross-entropy
-
--
-
L2=−z=1∑Zlogp(yz∣y<z,ht′,V)
-
-
-
-
-
-
- Experiment
-
-- 采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
-
- Experimental Results
- Analyses
- conclusion
- 关注的问题
-
-- 预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
-- 建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
-
- 解决方法
-
-- 双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
-- 双层控制阅读器:策略到上下文流来生成策略约束响应
-
- 创新点 / 本文的优势
- 实验结论
- 有待提升的部分
+ Title: Feedback-Aware Double COntrolling Network for
+Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+双层反馈策略选择器:通过反馈信息预测策略
+双层控制阅读器:通过策略约束上下文响应
+策略词典:丰富策略的语义信息 ## Introduction ## Related Work ##
+Problem Formulation ## Approach
+上下文编码器
+
+- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
+
+双层反馈策略选择器
+
+- 策略选择
+
+- 输入
+
+- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
+- BlenderBot Encoder 编码策略S
+- EmoBERTa Encoder 编码上下文对话U
+
+- 公式
+
+- 上下文编码器(策略S同理):\[\boldsymbol{H}=\operatorname{Enc}_{cxt}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{H}=\left(\boldsymbol{u}_{1},...,
+\boldsymbol{u}_{T}\right)\],T为Token数
+
+- 情感编码器:\[\boldsymbol{E}=\operatorname{EmoBERTa}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{E}=\left(\boldsymbol{e}_{1},...,
+\boldsymbol{e}_{T}\right)\],T为Token数
+
+- 分类:\[\boldsymbol{o}=\operatorname{MLP}\left(\tanh
+\left(\boldsymbol{W}_{o}^{T}[\boldsymbol{s} ; \boldsymbol{c} ;
+\boldsymbol{r}]+\boldsymbol{b}_{\boldsymbol{o}}\right)\right)\]
+
+- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
+
+
+
+- 双层反馈
+
+- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
+- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
+- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr +
+uΔc【计算损失时,给予正向或负向的反馈】
+
+
+双控读取器(模仿情感聊天机器ECM)
+
+- context-to-strategy:利用上下文信息来选择上下文相关的策略
+
+- \[\boldsymbol{g}^{c} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{c}^{T} \boldsymbol{c} + \boldsymbol{b}_{c}
+\right)\]
+
+- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
+
+- \[\boldsymbol{g}^{o} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{o}^{T} \boldsymbol{o} + \boldsymbol{b}_{o}
+\right)\]
+
+- 残差连接:在原始信息和更新信息之间进行权衡
+
+- \[\begin{array}{r}
+o^{\prime}=(1-\beta) \cdot o+\beta \cdot g^{c} \otimes o \\
+h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
+\end{array}\]
+
+
+策略字典
+
+- 输入策略令牌的描述,
+而不是策略令牌,以便模型对策略进行更深入的理解
+- Encoder-Decoder
+之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC:
+A MIxed Strategy-Aware Model Integrating COMET for Emotional Support
+Conversation
+
+响应生成
+
+- BlenderBot Decoder:\[\boldsymbol{p}\left(y_{z} \mid
+\boldsymbol{y}_{<z}, \boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}_{y<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)\]
+
+联合训练
+
+- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
+
+- \[\mathcal{L}_{1}=\left\{\begin{array}{ccc}
+-\hat{o} \log
+\left(\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s>0 \\
+-\hat{o} \log
+\left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s \leq 0
+\end{array}\right.\\\]
+
+- 响应生成:标准交叉熵损失优化 cross-entropy
+
+- \[\mathcal{L}_{2}=-\sum_{z=1}^{Z} \log
+\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}_{<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)\]
+## Experiment
+
+
+采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
+## Experimental Results ## Analyses ## conclusion # 关注的问题
+
+
+预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
+建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
+# 解决方法
+双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
+双层控制阅读器:策略到上下文流来生成策略约束响应 # 创新点 /
+本文的优势
+
+实验结论
+有待提升的部分
@@ -483,7 +482,8 @@ true
+
+
diff --git a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
index ba9dd99..d96b209 100644
--- a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
+++ b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -141,7 +141,7 @@
-
+
@@ -254,142 +254,110 @@
- Title: A Knowledge Graph for Distress Management Conversations
-
- 论文速览
- Abstract
-
-- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
-- 提出HEAL知识图谱
-
-- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
-- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
-- 组成部分
-
-- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types
-- 104k Edge 连接:不同类型的节点之间的关系
-- 每个节点和41种情绪状态相关联
-
-
-
-
-
- Introduction
-
-- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
-- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
-- 相关工作
-
-- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
-
-
-- 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
-- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
-
-
-
- Related Work
-
-- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
-- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应
-
- Methodology
-
-- 数据集管理
-
-- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
-- 数据预处理
-
-
-- 概要
-
-- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
-
-
-- 凝聚聚类
-
-- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
-- 凝聚聚类法:递归地合并增加最小链接距离的簇对
-- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
-
-
-- 定义压力源
-
-- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
-- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
-
-
-- 期望、回复、反馈类型
-
-- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
-- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
-
-
-- 情感状态建模
-
-- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
-
-
-
- Statistical Analysis
-
-- HEAL知识图谱:2.2k集群节点和情感状态,104k连接
-- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
-
- Visualization and Interpretation
-
-- 表示大多数回答都是正向积极反馈
-
- Evaluating the Utility of HEAL in Responding to Distress Prompts
-
-- 获取共情响应
-
-- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
-- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
-
-
-- 自动评估
-
-- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
-- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
-
-
-- 人类评估【DOI: 10.18653/v1/d16-1230】
-
-- HEAL模型变现更好
-
-
-
- Discussion and Conclusion
-
-- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
-
-
- 关注的问题 / 本文的优势
-
-- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
-- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
-
- 解决方法 / 创新点
-
-- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
-- 统计和可视化分析,识别导致情绪强度降低的有利反应
-- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
-
- 实验结论
-
-- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
-- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
-- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
-
- 有待提升的部分
-
-- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
-- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
-- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
-
+ Title: A Knowledge Graph for Distress Management
+Conversations
+
+论文速览
+Abstract
+
+相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+
+- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
+- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
+- 组成部分
+
+- 22k Node 节点:识别不同类型的stressors, speaker expectations,
+responses, feedback types
+- 104k Edge 连接:不同类型的节点之间的关系
+- 每个节点和41种情绪状态相关联 ## Introduction
+
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+
+- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
+
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+
+- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
+- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
+## Related Work
+
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ##
+Methodology
+数据集管理
+
+- 采用reddit数据集,通过Pushshift
+API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
+- 数据预处理
+
+概要
+
+- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
+
+凝聚聚类
+
+- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
+- 凝聚聚类法:递归地合并增加最小链接距离的簇对
+- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
+
+定义压力源
+
+- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
+- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
+
+期望、回复、反馈类型
+
+- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
+- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
+
+情感状态建模
+
+- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
+## Statistical Analysis
+
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
+## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL
+in Responding to Distress Prompts
+获取共情响应
+
+- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
+- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
+
+自动评估
+
+- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
+- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
+
+人类评估【DOI: 10.18653/v1/d16-1230】
+
+- HEAL模型变现更好 ## Discussion and Conclusion
+
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
+关注的问题 / 本文的优势
+
+端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
+# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
+# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
+# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
@@ -478,7 +446,8 @@ true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Title: Control Globally, Understand Locally. A Global-to-Local Hierarchical Graph Network for Emotional Support Conversation.
-创新点:
-
-- 在 Encoder 和 Decoder 之间加了一层 GCNConv 和 RGCNConv
-
-
-
- 论文速览
- Abstract
-
-- 目前研究的缺陷
-
-- 关注序列上下文信息,忽略了全局原因和局部心理意图与其的层次关系
-
-
-- 本文
-
-- 提出了一个全局到局部的层次图网络来捕获多源信息(全局原因、局部意图和对话历史)并建模它们之间的层次关系,该网络由一个多源编码器、一个层次图推理器和一个全局引导解码器组成
-- 设计了一个新的训练目标来监测全局的语义信息
-
-
-
- Introduction
-
-- 探索求助者情绪问题的原因:全局地控制情感支持对话的整个流程
-- 了解求助者的心理意图:帮助系统局部了解求助者当前时的心理状态
-- 本文目标
-
-- 捕获全局原因和局部心理意图
-- 建模全局与局部之间的关系
-
-
-- 解决方法【全局到局部层次图网络GLHG】
-
-- 多源编码器:COMET提取局部心理意图
-- 层次图推理机:全局原因(对话级)、局部心理意图(句子级)和对话历史之间的层次关系进行建模
-- 解码器中设计了一个新的训练目标来监控全局原因的语义信息
-
-
-
- Related Work
-
-- 图建模对话
-
-- GCN 利用自我和对话者间依赖性来模拟会话上下文
-- EGAE 使用图网络捕获面向任务对话中的对话模式
-
-
-- 常识性知识
-
-- 与本人有关的心理状态:xReact、xIntent
-
-
-
- Approach
-
-- 问题定义
-- 多源编码器
-
-- BlenderBot Encoder + Max-pooling
-- 上下文 + 全局原因 + 局部原因
-
-
-- 分层图推理机
-
-- GAT 图注意力网络:其他邻域信息的特征传播到当前节点,具有确定节点之间重要性和相关性的优点
--
-
注意力函数(2017出版)
-
--
-
注意力机制
-
--
-
-
--
-
注意力机制
-
--
-
-
-
-
-- Global-guide 解码器
-
-- 响应生成
-
--
-
,v表示图神经网络得到的全局变量
-
-
-
-- 监督全局语义信息:预测问题类型
-
--
-
-
-
-
-
-
-- 联合训练
-
-- 对数似然损失+交叉熵损失
--
-
![img]()
-
-
-
-
- Experiments
-
-- 指标:plexity (PPL), BLEU-n (B-n), ROUGE-L (R-L), Distinct-1(D-1), and Distinct-2 (D-2)
-- 由于有了意图特征,提出建议更具体有效
-
- Conclusion
-
-- 全局到局部的层次图网络(Global-to-Local Hierarchical Graph network, GLHG)来捕获多源信息并从全局到局部的角度建模层次关系
-- 新的训练目标“预测Seeker遇到问题的类型”
-
- 关注的问题 / 本文的优势
- 解决方法 / 创新点
-
-- 多源编码器利用情境信息并将心理意图与COMET结合,捕获全局原因和局部意图
-- 分层图推理机在全局原因、局部心理意图和对话历史之间进行交互,建模不同层次的关系(hierarchical graph reasoner)
-
- 实验结论
- 有待提升的部分
+ Title: Control Globally, Understand Locally. A
+Global-to-Local Hierarchical Graph Network for Emotional Support
+Conversation.
+创新点:
+
+- 在 Encoder 和 Decoder 之间加了一层 GCNConv 和 RGCNConv
+
+
+
+论文速览
+Abstract
+
+目前研究的缺陷
+
+- 关注序列上下文信息,忽略了全局原因和局部心理意图与其的层次关系
+
+本文
+
+- 提出了一个全局到局部的层次图网络来捕获多源信息(全局原因、局部意图和对话历史)并建模它们之间的层次关系,该网络由一个多源编码器、一个层次图推理器和一个全局引导解码器组成
+- 设计了一个新的训练目标来监测全局的语义信息 ## Introduction
+
+探索求助者情绪问题的原因:全局地控制情感支持对话的整个流程
+了解求助者的心理意图:帮助系统局部了解求助者当前时的心理状态
+本文目标
+
+- 捕获全局原因和局部心理意图
+- 建模全局与局部之间的关系
+
+解决方法【全局到局部层次图网络GLHG】
+
+- 多源编码器:COMET提取局部心理意图
+- 层次图推理机:全局原因(对话级)、局部心理意图(句子级)和对话历史之间的层次关系进行建模
+- 解码器中设计了一个新的训练目标来监控全局原因的语义信息 ## Related
+Work
+
+图建模对话
+
+- GCN 利用自我和对话者间依赖性来模拟会话上下文
+- EGAE 使用图网络捕获面向任务对话中的对话模式
+
+常识性知识
+
+- 与本人有关的心理状态:xReact、xIntent ## Approach
+
+问题定义
+多源编码器
+
+- BlenderBot Encoder + Max-pooling
+- 上下文 + 全局原因 + 局部原因
+
+分层图推理机
+
+- GAT
+图注意力网络:其他邻域信息的特征传播到当前节点,具有确定节点之间重要性和相关性的优点
+
+注意力函数(2017出版)
+
+
+注意力机制
+![img]()
+
+注意力机制
+![img]()
+
+Global-guide 解码器
+
+- 响应生成
+
+
+,v表示图神经网络得到的全局变量
+
+- 监督全局语义信息:预测问题类型
+
+![img]()
+
+
+联合训练
+
+- 对数似然损失+交叉熵损失
+
+
+Experiments
+
+指标:plexity (PPL), BLEU-n (B-n), ROUGE-L (R-L),
+Distinct-1(D-1), and Distinct-2 (D-2)
+由于有了意图特征,提出建议更具体有效 ## Conclusion
+全局到局部的层次图网络(Global-to-Local Hierarchical Graph
+network, GLHG)来捕获多源信息并从全局到局部的角度建模层次关系
+新的训练目标“预测Seeker遇到问题的类型” # 关注的问题 /
+本文的优势
+
+解决方法 / 创新点
+
+- 多源编码器利用情境信息并将心理意图与COMET结合,捕获全局原因和局部意图
+- 分层图推理机在全局原因、局部心理意图和对话历史之间进行交互,建模不同层次的关系(hierarchical
+graph reasoner) # 实验结论
+
+有待提升的部分
@@ -482,7 +452,8 @@ true
+
+
diff --git a/2023/DQ-HGAN/index.html b/2023/DQ-HGAN/index.html
index dc6d419..5c1a3d6 100644
--- a/2023/DQ-HGAN/index.html
+++ b/2023/DQ-HGAN/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,7 @@
-
+
@@ -260,144 +260,124 @@
- Title: A heterogeneous graph attention network based deep Q-learning for emotional support conversation generation
-
- 论文速览
- Abstract
-
-- 关注的问题
-
-- 动态建模对用户状态,包含个体的意图和情感
-- 综合各类因素选择最合适的支持策略
-
-
-- 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
-
-- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络
-- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法
-
-
-
- Introduction
-
-- 目前研究
-
-- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。
-
-
-- 关注的问题
-
-- 建模用户状态
-- 选择最优策略,以产生有效的保障响应
-
-
-- 提出的方法
-
-- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边
-- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达
-- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。
-
-
-- 主要贡献
-
-- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化
-- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态
-- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应
-- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应
-
-
-
- Related Work
-
-- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
-
-- 多头注意力机制
-
-- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力
-- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差
-
-
-- 词典
-
-- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义
-
-
-
-
-- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
-
-- 同构图【忽略了用户意图和情感的异构性】
-
-- GAT 图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互
-- GCN 图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖
-
-
-- 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。
-
-
-- 策略选择
-
-- 基于规则或启发式方法
-- 强化学习方法(如:Q-learning)
-
-- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应
-
-
-
-
-- 响应生成
-
-- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略
-
-
-
- Preliminaries
-
-- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中
-- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性
-- ATOMIC:得到意图或目的(xIntent)
-- NRC VAD 词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance)
-- 问题定义:上下文+策略+Query =>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
-
- Method
-
- 多源编码器
-
-
--
-
transformer编码器(TransformerEncoder)
-
-- ht = TransformerEncoder(Ht)
-
-
--
-
意图词典(COMET):通过对ATOMIC 微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
-
--
-
gt=TransformerEncoder(wi∈F∑softmax(ciTht)ci)
-
-
-
--
-
情感分类器(NRC VAD词典)
-
--
-
et=TransformerEncoder(wk∈Z∑softmax(zkTht)gt)
-
-
-
-
- 基于异构图的用户状态跟踪![img]()
- DQN强化学习![img]()
- 响应生成解码器![img]()
- Experiments
-Conclusion
- 关注的问题 / 本文的优势
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
+ Title: A heterogeneous graph attention network based
+deep Q-learning for emotional support conversation generation
+
+论文速览
+Abstract
+
+- 关注的问题
+
+- 动态建模对用户状态,包含个体的意图和情感
+- 综合各类因素选择最合适的支持策略
+
+- 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
+
+- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络
+- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法
+## Introduction
+
+- 目前研究
+
+- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。
+
+- 关注的问题
+
+- 建模用户状态
+- 选择最优策略,以产生有效的保障响应
+
+- 提出的方法
+
+- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边
+- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达
+- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。
+
+- 主要贡献
+
+- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化
+- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态
+- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应
+- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep
+Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应
+## Related Work
+
+- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
+
+- 多头注意力机制
+
+- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力
+- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差
+
+- 词典
+
+- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义
+
+
+- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
+
+- 同构图【忽略了用户意图和情感的异构性】
+
+- GAT
+图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互
+- GCN
+图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖
+
+- 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。
+
+- 策略选择
+
+- 基于规则或启发式方法
+- 强化学习方法(如:Q-learning)
+
+- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应
+
+
+- 响应生成
+
+- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略
+## Preliminaries
+
+- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中
+- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性
+- ATOMIC:得到意图或目的(xIntent)
+- NRC VAD
+词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance)
+- 问题定义:上下文+策略+Query
+=>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
+## Method
![88c61f5be72a795a087441904fcd0ad9_3_Figure_2_780332990.png]()
+
+多源编码器
+
+
+- transformer编码器(TransformerEncoder)
+
+- ht = TransformerEncoder(Ht)
+
+- 意图词典(COMET):通过对ATOMIC
+微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
+
+- \[g_{t}=TransformerEncoder\left(\sum_{w_{i}\in\mathscr{F}}\operatorname{softmax}\left(c_{i}^{T}
+h_{t}\right)c_{i}\right) \]
+
+- 情感分类器(NRC VAD词典)
+
+- \[e_{t}=\text{TransformerEncoder}\left(\sum_{w_{k}
+\in \mathscr{Z}}\operatorname{softmax}\left(z_{k}^{T} h_{t}\right)
+g_{t}\right) \text { }\]
+
+
+基于异构图的用户状态跟踪![img]()
+DQN强化学习![img]()
+响应生成解码器![img]()
+Experiments
+Conclusion
+关注的问题 / 本文的优势
+解决方法 / 创新点
+实验结论
+有待提升的部分
@@ -486,7 +466,8 @@ true
+
+
diff --git a/2023/FADO/index.html b/2023/FADO/index.html
index 5d957f8..bcc1fa7 100644
--- a/2023/FADO/index.html
+++ b/2023/FADO/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,147 +255,146 @@
- Title: Feedback-Aware Double COntrolling Network for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 双层反馈策略选择器:通过反馈信息预测策略
-- 双层控制阅读器:通过策略约束上下文响应
-- 策略词典:丰富策略的语义信息
-
- Introduction
- Related Work
- Problem Formulation
- Approach
-
-- 上下文编码器
-
-- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
-
-
-- 双层反馈策略选择器
-
-- 策略选择
-
-- 输入
-
-- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
-- BlenderBot Encoder 编码策略S
-- EmoBERTa Encoder 编码上下文对话U
-
-
-- 公式
-
-- 上下文编码器(策略S同理):$$\boldsymbol{H}=\operatorname{Enc}{cxt}\left(\boldsymbol{[CLS]}, \boldsymbol{u}{1}, \boldsymbol{[SEP]}, \boldsymbol{u}{2}, …, \boldsymbol{u}{M}\right)$$,M为对话数
-
--
-\boldsymbol{H}=\left(\boldsymbol{u}_{1},..., \boldsymbol{u}_{T}\right)$$,T为Token数
-
-
--
-\boldsymbol{E}=\left(\boldsymbol{e}_{1},..., \boldsymbol{e}_{T}\right)$$,T为Token数
-
-
-- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
-
-
-
-
-
-
-- 双层反馈
-
-- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
-- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
-- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr + uΔc【计算损失时,给予正向或负向的反馈】
-
-
-
-
-- 双控读取器(模仿情感聊天机器ECM)
-
-- context-to-strategy:利用上下文信息来选择上下文相关的策略
-
--
-\boldsymbol{g}^{c} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
-
--
-\boldsymbol{g}^{o} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- 残差连接:在原始信息和更新信息之间进行权衡
-
--
-\begin{array}{r}
-
-
-
-h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
-\end{array}$$
-
-
-- 策略字典
-
-- 输入策略令牌的描述, 而不是策略令牌,以便模型对策略进行更深入的理解
-- Encoder-Decoder 之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
-- 响应生成
-
-- BlenderBot Decoder:$$\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}{<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}{y<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)$$
-
-
-- 联合训练
-
-- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
-
--
-\mathcal{L}_{1}=\left\{\begin{array}{ccc}
-
-
-
--\hat{o} \log \left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right) & \text { if } & \Delta s \leq 0
-\end{array}\right.\$$
-- 响应生成:标准交叉熵损失优化 cross-entropy
-
--
-
L2=−z=1∑Zlogp(yz∣y<z,ht′,V)
-
-
-
-
-
-
- Experiment
-
-- 采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
-
- Experimental Results
- Analyses
- conclusion
- 关注的问题
-
-- 预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
-- 建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
-
- 解决方法
-
-- 双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
-- 双层控制阅读器:策略到上下文流来生成策略约束响应
-
- 创新点 / 本文的优势
- 实验结论
- 有待提升的部分
+ Title: Feedback-Aware Double COntrolling Network for
+Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+双层反馈策略选择器:通过反馈信息预测策略
+双层控制阅读器:通过策略约束上下文响应
+策略词典:丰富策略的语义信息 ## Introduction ## Related Work ##
+Problem Formulation ## Approach
+上下文编码器
+
+- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
+
+双层反馈策略选择器
+
+- 策略选择
+
+- 输入
+
+- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
+- BlenderBot Encoder 编码策略S
+- EmoBERTa Encoder 编码上下文对话U
+
+- 公式
+
+- 上下文编码器(策略S同理):\[\boldsymbol{H}=\operatorname{Enc}_{cxt}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{H}=\left(\boldsymbol{u}_{1},...,
+\boldsymbol{u}_{T}\right)\],T为Token数
+
+- 情感编码器:\[\boldsymbol{E}=\operatorname{EmoBERTa}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{E}=\left(\boldsymbol{e}_{1},...,
+\boldsymbol{e}_{T}\right)\],T为Token数
+
+- 分类:\[\boldsymbol{o}=\operatorname{MLP}\left(\tanh
+\left(\boldsymbol{W}_{o}^{T}[\boldsymbol{s} ; \boldsymbol{c} ;
+\boldsymbol{r}]+\boldsymbol{b}_{\boldsymbol{o}}\right)\right)\]
+
+- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
+
+
+
+- 双层反馈
+
+- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
+- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
+- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr +
+uΔc【计算损失时,给予正向或负向的反馈】
+
+
+双控读取器(模仿情感聊天机器ECM)
+
+- context-to-strategy:利用上下文信息来选择上下文相关的策略
+
+- \[\boldsymbol{g}^{c} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{c}^{T} \boldsymbol{c} + \boldsymbol{b}_{c}
+\right)\]
+
+- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
+
+- \[\boldsymbol{g}^{o} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{o}^{T} \boldsymbol{o} + \boldsymbol{b}_{o}
+\right)\]
+
+- 残差连接:在原始信息和更新信息之间进行权衡
+
+- \[\begin{array}{r}
+o^{\prime}=(1-\beta) \cdot o+\beta \cdot g^{c} \otimes o \\
+h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
+\end{array}\]
+
+
+策略字典
+
+- 输入策略令牌的描述,
+而不是策略令牌,以便模型对策略进行更深入的理解
+- Encoder-Decoder
+之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC:
+A MIxed Strategy-Aware Model Integrating COMET for Emotional Support
+Conversation
+
+响应生成
+
+- BlenderBot Decoder:\[\boldsymbol{p}\left(y_{z} \mid
+\boldsymbol{y}_{<z}, \boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}_{y<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)\]
+
+联合训练
+
+- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
+
+- \[\mathcal{L}_{1}=\left\{\begin{array}{ccc}
+-\hat{o} \log
+\left(\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s>0 \\
+-\hat{o} \log
+\left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s \leq 0
+\end{array}\right.\\\]
+
+- 响应生成:标准交叉熵损失优化 cross-entropy
+
+- \[\mathcal{L}_{2}=-\sum_{z=1}^{Z} \log
+\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}_{<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)\]
+## Experiment
+
+
+采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
+## Experimental Results ## Analyses ## conclusion # 关注的问题
+
+
+预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
+建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
+# 解决方法
+双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
+双层控制阅读器:策略到上下文流来生成策略约束响应 # 创新点 /
+本文的优势
+
+实验结论
+有待提升的部分
@@ -483,7 +482,8 @@ true
+
+
diff --git a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
index ba9dd99..d96b209 100644
--- a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
+++ b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -141,7 +141,7 @@
-
+
@@ -254,142 +254,110 @@
- Title: A Knowledge Graph for Distress Management Conversations
-
- 论文速览
- Abstract
-
-- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
-- 提出HEAL知识图谱
-
-- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
-- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
-- 组成部分
-
-- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types
-- 104k Edge 连接:不同类型的节点之间的关系
-- 每个节点和41种情绪状态相关联
-
-
-
-
-
- Introduction
-
-- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
-- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
-- 相关工作
-
-- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
-
-
-- 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
-- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
-
-
-
- Related Work
-
-- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
-- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应
-
- Methodology
-
-- 数据集管理
-
-- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
-- 数据预处理
-
-
-- 概要
-
-- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
-
-
-- 凝聚聚类
-
-- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
-- 凝聚聚类法:递归地合并增加最小链接距离的簇对
-- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
-
-
-- 定义压力源
-
-- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
-- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
-
-
-- 期望、回复、反馈类型
-
-- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
-- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
-
-
-- 情感状态建模
-
-- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
-
-
-
- Statistical Analysis
-
-- HEAL知识图谱:2.2k集群节点和情感状态,104k连接
-- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
-
- Visualization and Interpretation
-
-- 表示大多数回答都是正向积极反馈
-
- Evaluating the Utility of HEAL in Responding to Distress Prompts
-
-- 获取共情响应
-
-- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
-- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
-
-
-- 自动评估
-
-- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
-- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
-
-
-- 人类评估【DOI: 10.18653/v1/d16-1230】
-
-- HEAL模型变现更好
-
-
-
- Discussion and Conclusion
-
-- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
-
-
- 关注的问题 / 本文的优势
-
-- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
-- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
-
- 解决方法 / 创新点
-
-- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
-- 统计和可视化分析,识别导致情绪强度降低的有利反应
-- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
-
- 实验结论
-
-- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
-- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
-- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
-
- 有待提升的部分
-
-- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
-- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
-- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
-
+ Title: A Knowledge Graph for Distress Management
+Conversations
+
+论文速览
+Abstract
+
+相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+
+- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
+- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
+- 组成部分
+
+- 22k Node 节点:识别不同类型的stressors, speaker expectations,
+responses, feedback types
+- 104k Edge 连接:不同类型的节点之间的关系
+- 每个节点和41种情绪状态相关联 ## Introduction
+
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+
+- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
+
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+
+- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
+- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
+## Related Work
+
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ##
+Methodology
+数据集管理
+
+- 采用reddit数据集,通过Pushshift
+API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
+- 数据预处理
+
+概要
+
+- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
+
+凝聚聚类
+
+- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
+- 凝聚聚类法:递归地合并增加最小链接距离的簇对
+- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
+
+定义压力源
+
+- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
+- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
+
+期望、回复、反馈类型
+
+- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
+- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
+
+情感状态建模
+
+- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
+## Statistical Analysis
+
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
+## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL
+in Responding to Distress Prompts
+获取共情响应
+
+- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
+- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
+
+自动评估
+
+- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
+- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
+
+人类评估【DOI: 10.18653/v1/d16-1230】
+
+- HEAL模型变现更好 ## Discussion and Conclusion
+
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
+关注的问题 / 本文的优势
+
+端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
+# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
+# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
+# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
@@ -478,7 +446,8 @@ true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: Control Globally, Understand Locally. A Global-to-Local Hierarchical Graph Network for Emotional Support Conversation.
-创新点:
--
-
- 在 Encoder 和 Decoder 之间加了一层 GCNConv 和 RGCNConv -

论文速览
-Abstract
--
-
- 目前研究的缺陷
-
-
-
- 关注序列上下文信息,忽略了全局原因和局部心理意图与其的层次关系 -
- - 本文
-
-
-
- 提出了一个全局到局部的层次图网络来捕获多源信息(全局原因、局部意图和对话历史)并建模它们之间的层次关系,该网络由一个多源编码器、一个层次图推理器和一个全局引导解码器组成 -
- 设计了一个新的训练目标来监测全局的语义信息 -
-
Introduction
--
-
- 探索求助者情绪问题的原因:全局地控制情感支持对话的整个流程 -
- 了解求助者的心理意图:帮助系统局部了解求助者当前时的心理状态 -
- 本文目标
-
-
-
- 捕获全局原因和局部心理意图 -
- 建模全局与局部之间的关系 -
- - 解决方法【全局到局部层次图网络GLHG】
-
-
-
- 多源编码器:COMET提取局部心理意图 -
- 层次图推理机:全局原因(对话级)、局部心理意图(句子级)和对话历史之间的层次关系进行建模 -
- 解码器中设计了一个新的训练目标来监控全局原因的语义信息 -
-
Related Work
--
-
- 图建模对话
-
-
-
- GCN 利用自我和对话者间依赖性来模拟会话上下文 -
- EGAE 使用图网络捕获面向任务对话中的对话模式 -
- - 常识性知识
-
-
-
- 与本人有关的心理状态:xReact、xIntent -
-
Approach
--
-
- 问题定义 -
- 多源编码器
-
-
-
- BlenderBot Encoder + Max-pooling -
- 上下文 + 全局原因 + 局部原因 -
- - 分层图推理机
-
-
-
- GAT 图注意力网络:其他邻域信息的特征传播到当前节点,具有确定节点之间重要性和相关性的优点 -
-
-
注意力函数(2017出版) -
- -
-
注意力机制 -
- -
-
-
- -
-
注意力机制 -
- -
-
-
-
- - Global-guide 解码器
-
-
-
- 响应生成
-
-
-
-
-
,v表示图神经网络得到的全局变量 -
-
- -
-
- 监督全局语义信息:预测问题类型
-
-
-
-
-
-
-
- -
-
- - 响应生成
-
- 联合训练
-
-
-
- 对数似然损失+交叉熵损失 -
-
-
-
-
-
Experiments
--
-
- 指标:plexity (PPL), BLEU-n (B-n), ROUGE-L (R-L), Distinct-1(D-1), and Distinct-2 (D-2) -
- 由于有了意图特征,提出建议更具体有效 -
Conclusion
--
-
- 全局到局部的层次图网络(Global-to-Local Hierarchical Graph network, GLHG)来捕获多源信息并从全局到局部的角度建模层次关系 -
- 新的训练目标“预测Seeker遇到问题的类型” -
关注的问题 / 本文的优势
-解决方法 / 创新点
--
-
- 多源编码器利用情境信息并将心理意图与COMET结合,捕获全局原因和局部意图 -
- 分层图推理机在全局原因、局部心理意图和对话历史之间进行交互,建模不同层次的关系(hierarchical graph reasoner) -
实验结论
-有待提升的部分
+Title: Control Globally, Understand Locally. A +Global-to-Local Hierarchical Graph Network for Emotional Support +Conversation.
+创新点:
+-
+
- 在 Encoder 和 Decoder 之间加了一层 GCNConv 和 RGCNConv +

论文速览
+Abstract
+-
+
目前研究的缺陷
+-
+
- 关注序列上下文信息,忽略了全局原因和局部心理意图与其的层次关系 +
+本文
+-
+
- 提出了一个全局到局部的层次图网络来捕获多源信息(全局原因、局部意图和对话历史)并建模它们之间的层次关系,该网络由一个多源编码器、一个层次图推理器和一个全局引导解码器组成 +
- 设计了一个新的训练目标来监测全局的语义信息 ## Introduction +
+探索求助者情绪问题的原因:全局地控制情感支持对话的整个流程
+了解求助者的心理意图:帮助系统局部了解求助者当前时的心理状态
+本文目标
+-
+
- 捕获全局原因和局部心理意图 +
- 建模全局与局部之间的关系 +
+解决方法【全局到局部层次图网络GLHG】
+-
+
- 多源编码器:COMET提取局部心理意图 +
- 层次图推理机:全局原因(对话级)、局部心理意图(句子级)和对话历史之间的层次关系进行建模 +
- 解码器中设计了一个新的训练目标来监控全局原因的语义信息 ## Related +Work +
+图建模对话
+-
+
- GCN 利用自我和对话者间依赖性来模拟会话上下文 +
- EGAE 使用图网络捕获面向任务对话中的对话模式 +
+常识性知识
+-
+
- 与本人有关的心理状态:xReact、xIntent ## Approach +
+问题定义
+多源编码器
+-
+
- BlenderBot Encoder + Max-pooling +
- 上下文 + 全局原因 + 局部原因 +
+分层图推理机
+-
+
- GAT +图注意力网络:其他邻域信息的特征传播到当前节点,具有确定节点之间重要性和相关性的优点 +
+注意力函数(2017出版)
++
+注意力机制
++注意力机制
+
+Global-guide 解码器
+-
+
- 响应生成
+
-
+
+,v表示图神经网络得到的全局变量
+
+ - 监督全局语义信息:预测问题类型
+
-
+
+
+- 响应生成
+
联合训练
+-
+
- 对数似然损失+交叉熵损失 +
+
+
Experiments
+
+指标:plexity (PPL), BLEU-n (B-n), ROUGE-L (R-L), +Distinct-1(D-1), and Distinct-2 (D-2)
+由于有了意图特征,提出建议更具体有效 ## Conclusion
+全局到局部的层次图网络(Global-to-Local Hierarchical Graph +network, GLHG)来捕获多源信息并从全局到局部的角度建模层次关系
+新的训练目标“预测Seeker遇到问题的类型” # 关注的问题 / +本文的优势
+
解决方法 / 创新点
+-
+
- 多源编码器利用情境信息并将心理意图与COMET结合,捕获全局原因和局部意图 +
- 分层图推理机在全局原因、局部心理意图和对话历史之间进行交互,建模不同层次的关系(hierarchical +graph reasoner) # 实验结论 +
有待提升的部分
true
+
+
diff --git a/2023/DQ-HGAN/index.html b/2023/DQ-HGAN/index.html
index dc6d419..5c1a3d6 100644
--- a/2023/DQ-HGAN/index.html
+++ b/2023/DQ-HGAN/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,7 @@
-
+
@@ -260,144 +260,124 @@
- Title: A heterogeneous graph attention network based deep Q-learning for emotional support conversation generation
-
- 论文速览
- Abstract
-
-- 关注的问题
-
-- 动态建模对用户状态,包含个体的意图和情感
-- 综合各类因素选择最合适的支持策略
-
-
-- 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
-
-- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络
-- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法
-
-
-
- Introduction
-
-- 目前研究
-
-- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。
-
-
-- 关注的问题
-
-- 建模用户状态
-- 选择最优策略,以产生有效的保障响应
-
-
-- 提出的方法
-
-- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边
-- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达
-- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。
-
-
-- 主要贡献
-
-- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化
-- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态
-- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应
-- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应
-
-
-
- Related Work
-
-- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
-
-- 多头注意力机制
-
-- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力
-- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差
-
-
-- 词典
-
-- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义
-
-
-
-
-- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
-
-- 同构图【忽略了用户意图和情感的异构性】
-
-- GAT 图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互
-- GCN 图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖
-
-
-- 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。
-
-
-- 策略选择
-
-- 基于规则或启发式方法
-- 强化学习方法(如:Q-learning)
-
-- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应
-
-
-
-
-- 响应生成
-
-- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略
-
-
-
- Preliminaries
-
-- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中
-- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性
-- ATOMIC:得到意图或目的(xIntent)
-- NRC VAD 词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance)
-- 问题定义:上下文+策略+Query =>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
-
- Method
-
- 多源编码器
-
-
--
-
transformer编码器(TransformerEncoder)
-
-- ht = TransformerEncoder(Ht)
-
-
--
-
意图词典(COMET):通过对ATOMIC 微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
-
--
-
gt=TransformerEncoder(wi∈F∑softmax(ciTht)ci)
-
-
-
--
-
情感分类器(NRC VAD词典)
-
--
-
et=TransformerEncoder(wk∈Z∑softmax(zkTht)gt)
-
-
-
-
- 基于异构图的用户状态跟踪![img]()
- DQN强化学习![img]()
- 响应生成解码器![img]()
- Experiments
-Conclusion
- 关注的问题 / 本文的优势
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
+ Title: A heterogeneous graph attention network based
+deep Q-learning for emotional support conversation generation
+
+论文速览
+Abstract
+
+- 关注的问题
+
+- 动态建模对用户状态,包含个体的意图和情感
+- 综合各类因素选择最合适的支持策略
+
+- 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
+
+- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络
+- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法
+## Introduction
+
+- 目前研究
+
+- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。
+
+- 关注的问题
+
+- 建模用户状态
+- 选择最优策略,以产生有效的保障响应
+
+- 提出的方法
+
+- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边
+- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达
+- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。
+
+- 主要贡献
+
+- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化
+- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态
+- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应
+- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep
+Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应
+## Related Work
+
+- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
+
+- 多头注意力机制
+
+- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力
+- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差
+
+- 词典
+
+- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义
+
+
+- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
+
+- 同构图【忽略了用户意图和情感的异构性】
+
+- GAT
+图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互
+- GCN
+图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖
+
+- 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。
+
+- 策略选择
+
+- 基于规则或启发式方法
+- 强化学习方法(如:Q-learning)
+
+- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应
+
+
+- 响应生成
+
+- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略
+## Preliminaries
+
+- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中
+- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性
+- ATOMIC:得到意图或目的(xIntent)
+- NRC VAD
+词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance)
+- 问题定义:上下文+策略+Query
+=>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
+## Method
![88c61f5be72a795a087441904fcd0ad9_3_Figure_2_780332990.png]()
+
+多源编码器
+
+
+- transformer编码器(TransformerEncoder)
+
+- ht = TransformerEncoder(Ht)
+
+- 意图词典(COMET):通过对ATOMIC
+微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
+
+- \[g_{t}=TransformerEncoder\left(\sum_{w_{i}\in\mathscr{F}}\operatorname{softmax}\left(c_{i}^{T}
+h_{t}\right)c_{i}\right) \]
+
+- 情感分类器(NRC VAD词典)
+
+- \[e_{t}=\text{TransformerEncoder}\left(\sum_{w_{k}
+\in \mathscr{Z}}\operatorname{softmax}\left(z_{k}^{T} h_{t}\right)
+g_{t}\right) \text { }\]
+
+
+基于异构图的用户状态跟踪![img]()
+DQN强化学习![img]()
+响应生成解码器![img]()
+Experiments
+Conclusion
+关注的问题 / 本文的优势
+解决方法 / 创新点
+实验结论
+有待提升的部分
@@ -486,7 +466,8 @@ true
+
+
diff --git a/2023/FADO/index.html b/2023/FADO/index.html
index 5d957f8..bcc1fa7 100644
--- a/2023/FADO/index.html
+++ b/2023/FADO/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,147 +255,146 @@
- Title: Feedback-Aware Double COntrolling Network for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 双层反馈策略选择器:通过反馈信息预测策略
-- 双层控制阅读器:通过策略约束上下文响应
-- 策略词典:丰富策略的语义信息
-
- Introduction
- Related Work
- Problem Formulation
- Approach
-
-- 上下文编码器
-
-- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
-
-
-- 双层反馈策略选择器
-
-- 策略选择
-
-- 输入
-
-- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
-- BlenderBot Encoder 编码策略S
-- EmoBERTa Encoder 编码上下文对话U
-
-
-- 公式
-
-- 上下文编码器(策略S同理):$$\boldsymbol{H}=\operatorname{Enc}{cxt}\left(\boldsymbol{[CLS]}, \boldsymbol{u}{1}, \boldsymbol{[SEP]}, \boldsymbol{u}{2}, …, \boldsymbol{u}{M}\right)$$,M为对话数
-
--
-\boldsymbol{H}=\left(\boldsymbol{u}_{1},..., \boldsymbol{u}_{T}\right)$$,T为Token数
-
-
--
-\boldsymbol{E}=\left(\boldsymbol{e}_{1},..., \boldsymbol{e}_{T}\right)$$,T为Token数
-
-
-- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
-
-
-
-
-
-
-- 双层反馈
-
-- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
-- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
-- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr + uΔc【计算损失时,给予正向或负向的反馈】
-
-
-
-
-- 双控读取器(模仿情感聊天机器ECM)
-
-- context-to-strategy:利用上下文信息来选择上下文相关的策略
-
--
-\boldsymbol{g}^{c} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
-
--
-\boldsymbol{g}^{o} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- 残差连接:在原始信息和更新信息之间进行权衡
-
--
-\begin{array}{r}
-
-
-
-h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
-\end{array}$$
-
-
-- 策略字典
-
-- 输入策略令牌的描述, 而不是策略令牌,以便模型对策略进行更深入的理解
-- Encoder-Decoder 之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
-- 响应生成
-
-- BlenderBot Decoder:$$\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}{<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}{y<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)$$
-
-
-- 联合训练
-
-- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
-
--
-\mathcal{L}_{1}=\left\{\begin{array}{ccc}
-
-
-
--\hat{o} \log \left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right) & \text { if } & \Delta s \leq 0
-\end{array}\right.\$$
-- 响应生成:标准交叉熵损失优化 cross-entropy
-
--
-
L2=−z=1∑Zlogp(yz∣y<z,ht′,V)
-
-
-
-
-
-
- Experiment
-
-- 采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
-
- Experimental Results
- Analyses
- conclusion
- 关注的问题
-
-- 预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
-- 建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
-
- 解决方法
-
-- 双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
-- 双层控制阅读器:策略到上下文流来生成策略约束响应
-
- 创新点 / 本文的优势
- 实验结论
- 有待提升的部分
+ Title: Feedback-Aware Double COntrolling Network for
+Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+双层反馈策略选择器:通过反馈信息预测策略
+双层控制阅读器:通过策略约束上下文响应
+策略词典:丰富策略的语义信息 ## Introduction ## Related Work ##
+Problem Formulation ## Approach
+上下文编码器
+
+- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
+
+双层反馈策略选择器
+
+- 策略选择
+
+- 输入
+
+- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
+- BlenderBot Encoder 编码策略S
+- EmoBERTa Encoder 编码上下文对话U
+
+- 公式
+
+- 上下文编码器(策略S同理):\[\boldsymbol{H}=\operatorname{Enc}_{cxt}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{H}=\left(\boldsymbol{u}_{1},...,
+\boldsymbol{u}_{T}\right)\],T为Token数
+
+- 情感编码器:\[\boldsymbol{E}=\operatorname{EmoBERTa}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{E}=\left(\boldsymbol{e}_{1},...,
+\boldsymbol{e}_{T}\right)\],T为Token数
+
+- 分类:\[\boldsymbol{o}=\operatorname{MLP}\left(\tanh
+\left(\boldsymbol{W}_{o}^{T}[\boldsymbol{s} ; \boldsymbol{c} ;
+\boldsymbol{r}]+\boldsymbol{b}_{\boldsymbol{o}}\right)\right)\]
+
+- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
+
+
+
+- 双层反馈
+
+- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
+- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
+- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr +
+uΔc【计算损失时,给予正向或负向的反馈】
+
+
+双控读取器(模仿情感聊天机器ECM)
+
+- context-to-strategy:利用上下文信息来选择上下文相关的策略
+
+- \[\boldsymbol{g}^{c} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{c}^{T} \boldsymbol{c} + \boldsymbol{b}_{c}
+\right)\]
+
+- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
+
+- \[\boldsymbol{g}^{o} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{o}^{T} \boldsymbol{o} + \boldsymbol{b}_{o}
+\right)\]
+
+- 残差连接:在原始信息和更新信息之间进行权衡
+
+- \[\begin{array}{r}
+o^{\prime}=(1-\beta) \cdot o+\beta \cdot g^{c} \otimes o \\
+h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
+\end{array}\]
+
+
+策略字典
+
+- 输入策略令牌的描述,
+而不是策略令牌,以便模型对策略进行更深入的理解
+- Encoder-Decoder
+之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC:
+A MIxed Strategy-Aware Model Integrating COMET for Emotional Support
+Conversation
+
+响应生成
+
+- BlenderBot Decoder:\[\boldsymbol{p}\left(y_{z} \mid
+\boldsymbol{y}_{<z}, \boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}_{y<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)\]
+
+联合训练
+
+- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
+
+- \[\mathcal{L}_{1}=\left\{\begin{array}{ccc}
+-\hat{o} \log
+\left(\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s>0 \\
+-\hat{o} \log
+\left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s \leq 0
+\end{array}\right.\\\]
+
+- 响应生成:标准交叉熵损失优化 cross-entropy
+
+- \[\mathcal{L}_{2}=-\sum_{z=1}^{Z} \log
+\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}_{<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)\]
+## Experiment
+
+
+采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
+## Experimental Results ## Analyses ## conclusion # 关注的问题
+
+
+预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
+建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
+# 解决方法
+双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
+双层控制阅读器:策略到上下文流来生成策略约束响应 # 创新点 /
+本文的优势
+
+实验结论
+有待提升的部分
@@ -483,7 +482,8 @@ true
+
+
diff --git a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
index ba9dd99..d96b209 100644
--- a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
+++ b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -141,7 +141,7 @@
-
+
@@ -254,142 +254,110 @@
- Title: A Knowledge Graph for Distress Management Conversations
-
- 论文速览
- Abstract
-
-- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
-- 提出HEAL知识图谱
-
-- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
-- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
-- 组成部分
-
-- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types
-- 104k Edge 连接:不同类型的节点之间的关系
-- 每个节点和41种情绪状态相关联
-
-
-
-
-
- Introduction
-
-- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
-- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
-- 相关工作
-
-- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
-
-
-- 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
-- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
-
-
-
- Related Work
-
-- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
-- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应
-
- Methodology
-
-- 数据集管理
-
-- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
-- 数据预处理
-
-
-- 概要
-
-- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
-
-
-- 凝聚聚类
-
-- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
-- 凝聚聚类法:递归地合并增加最小链接距离的簇对
-- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
-
-
-- 定义压力源
-
-- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
-- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
-
-
-- 期望、回复、反馈类型
-
-- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
-- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
-
-
-- 情感状态建模
-
-- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
-
-
-
- Statistical Analysis
-
-- HEAL知识图谱:2.2k集群节点和情感状态,104k连接
-- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
-
- Visualization and Interpretation
-
-- 表示大多数回答都是正向积极反馈
-
- Evaluating the Utility of HEAL in Responding to Distress Prompts
-
-- 获取共情响应
-
-- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
-- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
-
-
-- 自动评估
-
-- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
-- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
-
-
-- 人类评估【DOI: 10.18653/v1/d16-1230】
-
-- HEAL模型变现更好
-
-
-
- Discussion and Conclusion
-
-- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
-
-
- 关注的问题 / 本文的优势
-
-- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
-- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
-
- 解决方法 / 创新点
-
-- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
-- 统计和可视化分析,识别导致情绪强度降低的有利反应
-- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
-
- 实验结论
-
-- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
-- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
-- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
-
- 有待提升的部分
-
-- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
-- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
-- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
-
+ Title: A Knowledge Graph for Distress Management
+Conversations
+
+论文速览
+Abstract
+
+相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+
+- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
+- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
+- 组成部分
+
+- 22k Node 节点:识别不同类型的stressors, speaker expectations,
+responses, feedback types
+- 104k Edge 连接:不同类型的节点之间的关系
+- 每个节点和41种情绪状态相关联 ## Introduction
+
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+
+- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
+
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+
+- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
+- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
+## Related Work
+
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ##
+Methodology
+数据集管理
+
+- 采用reddit数据集,通过Pushshift
+API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
+- 数据预处理
+
+概要
+
+- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
+
+凝聚聚类
+
+- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
+- 凝聚聚类法:递归地合并增加最小链接距离的簇对
+- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
+
+定义压力源
+
+- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
+- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
+
+期望、回复、反馈类型
+
+- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
+- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
+
+情感状态建模
+
+- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
+## Statistical Analysis
+
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
+## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL
+in Responding to Distress Prompts
+获取共情响应
+
+- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
+- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
+
+自动评估
+
+- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
+- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
+
+人类评估【DOI: 10.18653/v1/d16-1230】
+
+- HEAL模型变现更好 ## Discussion and Conclusion
+
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
+关注的问题 / 本文的优势
+
+端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
+# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
+# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
+# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
@@ -478,7 +446,8 @@ true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Title: A heterogeneous graph attention network based deep Q-learning for emotional support conversation generation
-
- 论文速览
- Abstract
-
-- 关注的问题
-
-- 动态建模对用户状态,包含个体的意图和情感
-- 综合各类因素选择最合适的支持策略
-
-
-- 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
-
-- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络
-- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法
-
-
-
- Introduction
-
-- 目前研究
-
-- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。
-
-
-- 关注的问题
-
-- 建模用户状态
-- 选择最优策略,以产生有效的保障响应
-
-
-- 提出的方法
-
-- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边
-- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达
-- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。
-
-
-- 主要贡献
-
-- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化
-- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态
-- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应
-- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应
-
-
-
- Related Work
-
-- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
-
-- 多头注意力机制
-
-- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力
-- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差
-
-
-- 词典
-
-- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义
-
-
-
-
-- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
-
-- 同构图【忽略了用户意图和情感的异构性】
-
-- GAT 图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互
-- GCN 图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖
-
-
-- 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。
-
-
-- 策略选择
-
-- 基于规则或启发式方法
-- 强化学习方法(如:Q-learning)
-
-- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应
-
-
-
-
-- 响应生成
-
-- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略
-
-
-
- Preliminaries
-
-- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中
-- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性
-- ATOMIC:得到意图或目的(xIntent)
-- NRC VAD 词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance)
-- 问题定义:上下文+策略+Query =>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
-
- Method
-
- 多源编码器
-
-
--
-
transformer编码器(TransformerEncoder)
-
-- ht = TransformerEncoder(Ht)
-
-
--
-
意图词典(COMET):通过对ATOMIC 微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
-
--
-
gt=TransformerEncoder(wi∈F∑softmax(ciTht)ci)
-
-
-
--
-
情感分类器(NRC VAD词典)
-
--
-
et=TransformerEncoder(wk∈Z∑softmax(zkTht)gt)
-
-
-
-
- 基于异构图的用户状态跟踪![img]()
- DQN强化学习![img]()
- 响应生成解码器![img]()
- Experiments
-Conclusion
- 关注的问题 / 本文的优势
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
+ Title: A heterogeneous graph attention network based
+deep Q-learning for emotional support conversation generation
+
+论文速览
+Abstract
+
+- 关注的问题
+
+- 动态建模对用户状态,包含个体的意图和情感
+- 综合各类因素选择最合适的支持策略
+
+- 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
+
+- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络
+- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法
+## Introduction
+
+- 目前研究
+
+- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。
+
+- 关注的问题
+
+- 建模用户状态
+- 选择最优策略,以产生有效的保障响应
+
+- 提出的方法
+
+- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边
+- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达
+- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。
+
+- 主要贡献
+
+- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化
+- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态
+- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应
+- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep
+Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应
+## Related Work
+
+- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
+
+- 多头注意力机制
+
+- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力
+- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差
+
+- 词典
+
+- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义
+
+
+- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
+
+- 同构图【忽略了用户意图和情感的异构性】
+
+- GAT
+图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互
+- GCN
+图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖
+
+- 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。
+
+- 策略选择
+
+- 基于规则或启发式方法
+- 强化学习方法(如:Q-learning)
+
+- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应
+
+
+- 响应生成
+
+- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略
+## Preliminaries
+
+- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中
+- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性
+- ATOMIC:得到意图或目的(xIntent)
+- NRC VAD
+词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance)
+- 问题定义:上下文+策略+Query
+=>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
+## Method
![88c61f5be72a795a087441904fcd0ad9_3_Figure_2_780332990.png]()
+
+多源编码器
+
+
+- transformer编码器(TransformerEncoder)
+
+- ht = TransformerEncoder(Ht)
+
+- 意图词典(COMET):通过对ATOMIC
+微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
+
+- \[g_{t}=TransformerEncoder\left(\sum_{w_{i}\in\mathscr{F}}\operatorname{softmax}\left(c_{i}^{T}
+h_{t}\right)c_{i}\right) \]
+
+- 情感分类器(NRC VAD词典)
+
+- \[e_{t}=\text{TransformerEncoder}\left(\sum_{w_{k}
+\in \mathscr{Z}}\operatorname{softmax}\left(z_{k}^{T} h_{t}\right)
+g_{t}\right) \text { }\]
+
+
+基于异构图的用户状态跟踪![img]()
+DQN强化学习![img]()
+响应生成解码器![img]()
+Experiments
+Conclusion
+关注的问题 / 本文的优势
+解决方法 / 创新点
+实验结论
+有待提升的部分
@@ -486,7 +466,8 @@ true
+
+
diff --git a/2023/FADO/index.html b/2023/FADO/index.html
index 5d957f8..bcc1fa7 100644
--- a/2023/FADO/index.html
+++ b/2023/FADO/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,147 +255,146 @@
- Title: Feedback-Aware Double COntrolling Network for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 双层反馈策略选择器:通过反馈信息预测策略
-- 双层控制阅读器:通过策略约束上下文响应
-- 策略词典:丰富策略的语义信息
-
- Introduction
- Related Work
- Problem Formulation
- Approach
-
-- 上下文编码器
-
-- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
-
-
-- 双层反馈策略选择器
-
-- 策略选择
-
-- 输入
-
-- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
-- BlenderBot Encoder 编码策略S
-- EmoBERTa Encoder 编码上下文对话U
-
-
-- 公式
-
-- 上下文编码器(策略S同理):$$\boldsymbol{H}=\operatorname{Enc}{cxt}\left(\boldsymbol{[CLS]}, \boldsymbol{u}{1}, \boldsymbol{[SEP]}, \boldsymbol{u}{2}, …, \boldsymbol{u}{M}\right)$$,M为对话数
-
--
-\boldsymbol{H}=\left(\boldsymbol{u}_{1},..., \boldsymbol{u}_{T}\right)$$,T为Token数
-
-
--
-\boldsymbol{E}=\left(\boldsymbol{e}_{1},..., \boldsymbol{e}_{T}\right)$$,T为Token数
-
-
-- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
-
-
-
-
-
-
-- 双层反馈
-
-- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
-- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
-- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr + uΔc【计算损失时,给予正向或负向的反馈】
-
-
-
-
-- 双控读取器(模仿情感聊天机器ECM)
-
-- context-to-strategy:利用上下文信息来选择上下文相关的策略
-
--
-\boldsymbol{g}^{c} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
-
--
-\boldsymbol{g}^{o} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- 残差连接:在原始信息和更新信息之间进行权衡
-
--
-\begin{array}{r}
-
-
-
-h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
-\end{array}$$
-
-
-- 策略字典
-
-- 输入策略令牌的描述, 而不是策略令牌,以便模型对策略进行更深入的理解
-- Encoder-Decoder 之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
-- 响应生成
-
-- BlenderBot Decoder:$$\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}{<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}{y<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)$$
-
-
-- 联合训练
-
-- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
-
--
-\mathcal{L}_{1}=\left\{\begin{array}{ccc}
-
-
-
--\hat{o} \log \left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right) & \text { if } & \Delta s \leq 0
-\end{array}\right.\$$
-- 响应生成:标准交叉熵损失优化 cross-entropy
-
--
-
L2=−z=1∑Zlogp(yz∣y<z,ht′,V)
-
-
-
-
-
-
- Experiment
-
-- 采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
-
- Experimental Results
- Analyses
- conclusion
- 关注的问题
-
-- 预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
-- 建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
-
- 解决方法
-
-- 双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
-- 双层控制阅读器:策略到上下文流来生成策略约束响应
-
- 创新点 / 本文的优势
- 实验结论
- 有待提升的部分
+ Title: Feedback-Aware Double COntrolling Network for
+Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+双层反馈策略选择器:通过反馈信息预测策略
+双层控制阅读器:通过策略约束上下文响应
+策略词典:丰富策略的语义信息 ## Introduction ## Related Work ##
+Problem Formulation ## Approach
+上下文编码器
+
+- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
+
+双层反馈策略选择器
+
+- 策略选择
+
+- 输入
+
+- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
+- BlenderBot Encoder 编码策略S
+- EmoBERTa Encoder 编码上下文对话U
+
+- 公式
+
+- 上下文编码器(策略S同理):\[\boldsymbol{H}=\operatorname{Enc}_{cxt}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{H}=\left(\boldsymbol{u}_{1},...,
+\boldsymbol{u}_{T}\right)\],T为Token数
+
+- 情感编码器:\[\boldsymbol{E}=\operatorname{EmoBERTa}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{E}=\left(\boldsymbol{e}_{1},...,
+\boldsymbol{e}_{T}\right)\],T为Token数
+
+- 分类:\[\boldsymbol{o}=\operatorname{MLP}\left(\tanh
+\left(\boldsymbol{W}_{o}^{T}[\boldsymbol{s} ; \boldsymbol{c} ;
+\boldsymbol{r}]+\boldsymbol{b}_{\boldsymbol{o}}\right)\right)\]
+
+- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
+
+
+
+- 双层反馈
+
+- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
+- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
+- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr +
+uΔc【计算损失时,给予正向或负向的反馈】
+
+
+双控读取器(模仿情感聊天机器ECM)
+
+- context-to-strategy:利用上下文信息来选择上下文相关的策略
+
+- \[\boldsymbol{g}^{c} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{c}^{T} \boldsymbol{c} + \boldsymbol{b}_{c}
+\right)\]
+
+- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
+
+- \[\boldsymbol{g}^{o} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{o}^{T} \boldsymbol{o} + \boldsymbol{b}_{o}
+\right)\]
+
+- 残差连接:在原始信息和更新信息之间进行权衡
+
+- \[\begin{array}{r}
+o^{\prime}=(1-\beta) \cdot o+\beta \cdot g^{c} \otimes o \\
+h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
+\end{array}\]
+
+
+策略字典
+
+- 输入策略令牌的描述,
+而不是策略令牌,以便模型对策略进行更深入的理解
+- Encoder-Decoder
+之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC:
+A MIxed Strategy-Aware Model Integrating COMET for Emotional Support
+Conversation
+
+响应生成
+
+- BlenderBot Decoder:\[\boldsymbol{p}\left(y_{z} \mid
+\boldsymbol{y}_{<z}, \boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}_{y<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)\]
+
+联合训练
+
+- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
+
+- \[\mathcal{L}_{1}=\left\{\begin{array}{ccc}
+-\hat{o} \log
+\left(\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s>0 \\
+-\hat{o} \log
+\left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s \leq 0
+\end{array}\right.\\\]
+
+- 响应生成:标准交叉熵损失优化 cross-entropy
+
+- \[\mathcal{L}_{2}=-\sum_{z=1}^{Z} \log
+\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}_{<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)\]
+## Experiment
+
+
+采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
+## Experimental Results ## Analyses ## conclusion # 关注的问题
+
+
+预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
+建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
+# 解决方法
+双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
+双层控制阅读器:策略到上下文流来生成策略约束响应 # 创新点 /
+本文的优势
+
+实验结论
+有待提升的部分
@@ -483,7 +482,8 @@ true
+
+
diff --git a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
index ba9dd99..d96b209 100644
--- a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
+++ b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -141,7 +141,7 @@
-
+
@@ -254,142 +254,110 @@
- Title: A Knowledge Graph for Distress Management Conversations
-
- 论文速览
- Abstract
-
-- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
-- 提出HEAL知识图谱
-
-- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
-- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
-- 组成部分
-
-- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types
-- 104k Edge 连接:不同类型的节点之间的关系
-- 每个节点和41种情绪状态相关联
-
-
-
-
-
- Introduction
-
-- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
-- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
-- 相关工作
-
-- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
-
-
-- 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
-- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
-
-
-
- Related Work
-
-- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
-- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应
-
- Methodology
-
-- 数据集管理
-
-- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
-- 数据预处理
-
-
-- 概要
-
-- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
-
-
-- 凝聚聚类
-
-- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
-- 凝聚聚类法:递归地合并增加最小链接距离的簇对
-- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
-
-
-- 定义压力源
-
-- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
-- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
-
-
-- 期望、回复、反馈类型
-
-- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
-- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
-
-
-- 情感状态建模
-
-- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
-
-
-
- Statistical Analysis
-
-- HEAL知识图谱:2.2k集群节点和情感状态,104k连接
-- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
-
- Visualization and Interpretation
-
-- 表示大多数回答都是正向积极反馈
-
- Evaluating the Utility of HEAL in Responding to Distress Prompts
-
-- 获取共情响应
-
-- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
-- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
-
-
-- 自动评估
-
-- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
-- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
-
-
-- 人类评估【DOI: 10.18653/v1/d16-1230】
-
-- HEAL模型变现更好
-
-
-
- Discussion and Conclusion
-
-- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
-
-
- 关注的问题 / 本文的优势
-
-- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
-- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
-
- 解决方法 / 创新点
-
-- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
-- 统计和可视化分析,识别导致情绪强度降低的有利反应
-- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
-
- 实验结论
-
-- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
-- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
-- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
-
- 有待提升的部分
-
-- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
-- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
-- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
-
+ Title: A Knowledge Graph for Distress Management
+Conversations
+
+论文速览
+Abstract
+
+相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+
+- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
+- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
+- 组成部分
+
+- 22k Node 节点:识别不同类型的stressors, speaker expectations,
+responses, feedback types
+- 104k Edge 连接:不同类型的节点之间的关系
+- 每个节点和41种情绪状态相关联 ## Introduction
+
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+
+- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
+
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+
+- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
+- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
+## Related Work
+
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ##
+Methodology
+数据集管理
+
+- 采用reddit数据集,通过Pushshift
+API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
+- 数据预处理
+
+概要
+
+- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
+
+凝聚聚类
+
+- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
+- 凝聚聚类法:递归地合并增加最小链接距离的簇对
+- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
+
+定义压力源
+
+- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
+- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
+
+期望、回复、反馈类型
+
+- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
+- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
+
+情感状态建模
+
+- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
+## Statistical Analysis
+
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
+## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL
+in Responding to Distress Prompts
+获取共情响应
+
+- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
+- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
+
+自动评估
+
+- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
+- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
+
+人类评估【DOI: 10.18653/v1/d16-1230】
+
+- HEAL模型变现更好 ## Discussion and Conclusion
+
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
+关注的问题 / 本文的优势
+
+端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
+# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
+# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
+# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
@@ -478,7 +446,8 @@ true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: A heterogeneous graph attention network based deep Q-learning for emotional support conversation generation
- -论文速览
-Abstract
--
-
- 关注的问题
-
-
-
- 动态建模对用户状态,包含个体的意图和情感 -
- 综合各类因素选择最合适的支持策略 -
- - 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
-
-
-
- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络 -
- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法 -
-
Introduction
--
-
- 目前研究
-
-
-
- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。 -
- - 关注的问题
-
-
-
- 建模用户状态 -
- 选择最优策略,以产生有效的保障响应 -
- - 提出的方法
-
-
-
- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边 -
- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达 -
- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。 -
- - 主要贡献
-
-
-
- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化 -
- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态 -
- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应 -
- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应 -
-
Related Work
--
-
- 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
-
-
-
- 多头注意力机制
-
-
-
- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力 -
- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差 -
- - 词典
-
-
-
- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义 -
-
- - 多头注意力机制
-
- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
-
-
-
- 同构图【忽略了用户意图和情感的异构性】
-
-
-
- GAT 图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互 -
- GCN 图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖 -
- - 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。 -
- - 同构图【忽略了用户意图和情感的异构性】
-
- 策略选择
-
-
-
- 基于规则或启发式方法 -
- 强化学习方法(如:Q-learning)
-
-
-
- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应 -
-
- - 响应生成
-
-
-
- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略 -
-
Preliminaries
--
-
- ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中 -
- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性 -
- ATOMIC:得到意图或目的(xIntent) -
- NRC VAD 词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance) -
- 问题定义:上下文+策略+Query =>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测) -
Method
-
多源编码器
-
-
-
-
-
transformer编码器(TransformerEncoder)
--
-
- ht = TransformerEncoder(Ht) -
- -
-
意图词典(COMET):通过对ATOMIC 微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
--
-
-
-
gt=TransformerEncoder(wi∈F∑softmax(ciTht)ci)
-
-
- -
-
-
-
情感分类器(NRC VAD词典)
--
-
-
-
et=TransformerEncoder(wk∈Z∑softmax(zkTht)gt)
-
-
- -
-
基于异构图的用户状态跟踪![img]()
- DQN强化学习![img]()
- 响应生成解码器![img]()
-Experiments
-Conclusion
-关注的问题 / 本文的优势
-解决方法 / 创新点
-实验结论
-有待提升的部分
+Title: A heterogeneous graph attention network based +deep Q-learning for emotional support conversation generation
+ +论文速览
+Abstract
+-
+
- 关注的问题
+
-
+
- 动态建模对用户状态,包含个体的意图和情感 +
- 综合各类因素选择最合适的支持策略 +
+ - 提出的方法【基于异构图注意力网络的深度Q-learning情感支持对话生成】
+
-
+
- 为了捕获用户意图、情感和历史对话之间的交互关系,基于意图词典和情感分类器,构建了异构图注意力网络 +
- 采用基于DQN的最优响应策略以指导响应生成,优于传统的基于规则或启发式方法 +## Introduction +
+ - 目前研究
+
-
+
- ESC任务要求能够确定求助者的心理意图和情绪状态,以便提供适当的支持。因此整合意图识别和情感识别对于提高情感支持对话的质量至关重要,且目前的方法对用户状态建模不充分。 +
+ - 关注的问题
+
-
+
- 建模用户状态 +
- 选择最优策略,以产生有效的保障响应 +
+ - 提出的方法
+
-
+
- 设计了基于注意力的异构图网络,与用户的意图、情感和历史对话交互,可以有效地捕获和建模图中不同类型的节点和边 +
- 构建意图词典和情感分类器来捕捉求助者在语境中的细微情感表达 +
- DQN算法对用户未来反馈的期望值进行估计,帮助系统选择获得最优长期值的策略。其允许系统从用户的反馈中学习,调整其策略,以提供最有效的支持响应。 +
+ - 主要贡献
+
-
+
- 提出了一种新的方法DQ-HGAN,将意图和情感识别与策略生成相结合,以提高情感支持对话系统的质量和个性化 +
- 构建意图词典和情感分类器,捕捉求助者在语境中的细微情感表达并跟踪其状态 +
- 设计了一种基于注意力机制的异构图网络,与用户的意图、情感和历史对话进行交互,并选择最优的支持策略以生成有效的支持响应 +
- ESC生成中使用ESC生成中使用强化学习,具体来说,使用DQN算法(Deep +Q-Network)估计用户未来反馈的期望值,动态调整策略以提供最有效的支持响应 +## Related Work +
+ - 对话中的意图和情感识别【在模型中融合了“意图”这个特征】
+
-
+
- 多头注意力机制
+
-
+
- 多头注意力机制来捕捉用户的意图和情感。缺点:缺乏有效捕捉用户细微情感表达的能力 +
- 使用预训练模型,增强PLM对话相关性,识别对话意图、推断对话情感。缺点:不是专门为ESC任务定制的,性能差 +
+ - 词典
+
-
+
- 词典包含特定意图或情感相关的词汇和短语,利用基于规则的算法将context与意图词典进行匹配,并分配相应的意图标签。缺点:只将单个单词与标签匹配,可能会忽略整个句子的意图或情感含义 +
+
+ - 多头注意力机制
+
- 图建模【捕获会话系统中用户意图、情感和对话历史之间的复杂关系】
+
-
+
- 同构图【忽略了用户意图和情感的异构性】
+
-
+
- GAT +图注意力网络,利用自注意力机制来捕获对话图中意图和情感节点之间的交互 +
- GCN +图卷积网络,利用图结构在节点之间传播信息,并捕获对话数据中的上下文依赖 +
+ - 异构图注意力网络是专为表示图中不同类型的节点和边而设计的,它擅长对不同的节点类型进行建模,如用户话语、系统响应、情感状态和意图,从而更全面地了解用户的情感状态;还擅长捕捉不同类型的边,包括顺序依赖、自依赖和状态依赖,从而能够更准确地表示用户的情感状态。此外,它还包含了一种注意力机制来进行重要性加权,允许它在聚合过程中专注于最相关的信息,从而更全面地了解用户的状态。 +
+ - 同构图【忽略了用户意图和情感的异构性】
+
- 策略选择
+
-
+
- 基于规则或启发式方法 +
- 强化学习方法(如:Q-learning)
+
-
+
- 采用DQN估计不同对话动作的期望值,并学习了一种最大化该值的策略。从用户反馈中学习,并生成更有吸引力和信息量的响应 +
+
+ - 响应生成
+
-
+
- 目前流行的Encoder-Decoder模型往往专注于根据对话历史生成回复,而没有考虑用户的意图、情感以及合适的支持策略 +## Preliminaries +
+ - ESConv:标记对话,并将其转换为词嵌入,以将其输入到模型中 +
- COMET:使用COMET初始化模型的词嵌入,并在ESConv数据集上进行微调,以提高其构建意图词典的有效性 +
- ATOMIC:得到意图或目的(xIntent) +
- NRC VAD +词典:得到情感词典,每个单词对应的效价-觉醒-支配(Valence-Arousal-Dominance) +
- 问题定义:上下文+策略+Query
+=>响应Yt。最优策略基于当前状态和期望的长期回报(通过Q-learning预测)
+## Method
多源编码器
+
-
+
- transformer编码器(TransformerEncoder)
+
-
+
- ht = TransformerEncoder(Ht) +
+ - 意图词典(COMET):通过对ATOMIC
+微调,同去意图关键词,构建意图词典(意图关键词,对应的词嵌入)
+
-
+
- \[g_{t}=TransformerEncoder\left(\sum_{w_{i}\in\mathscr{F}}\operatorname{softmax}\left(c_{i}^{T} +h_{t}\right)c_{i}\right) \] +
+ - 情感分类器(NRC VAD词典)
+
-
+
- \[e_{t}=\text{TransformerEncoder}\left(\sum_{w_{k} +\in \mathscr{Z}}\operatorname{softmax}\left(z_{k}^{T} h_{t}\right) +g_{t}\right) \text { }\] +
+
基于异构图的用户状态跟踪![img]()
+DQN强化学习![img]()
+响应生成解码器![img]()
+Experiments
+Conclusion
+关注的问题 / 本文的优势
+解决方法 / 创新点
+实验结论
+有待提升的部分
true
+
+
diff --git a/2023/FADO/index.html b/2023/FADO/index.html
index 5d957f8..bcc1fa7 100644
--- a/2023/FADO/index.html
+++ b/2023/FADO/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,147 +255,146 @@
- Title: Feedback-Aware Double COntrolling Network for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 双层反馈策略选择器:通过反馈信息预测策略
-- 双层控制阅读器:通过策略约束上下文响应
-- 策略词典:丰富策略的语义信息
-
- Introduction
- Related Work
- Problem Formulation
- Approach
-
-- 上下文编码器
-
-- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
-
-
-- 双层反馈策略选择器
-
-- 策略选择
-
-- 输入
-
-- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
-- BlenderBot Encoder 编码策略S
-- EmoBERTa Encoder 编码上下文对话U
-
-
-- 公式
-
-- 上下文编码器(策略S同理):$$\boldsymbol{H}=\operatorname{Enc}{cxt}\left(\boldsymbol{[CLS]}, \boldsymbol{u}{1}, \boldsymbol{[SEP]}, \boldsymbol{u}{2}, …, \boldsymbol{u}{M}\right)$$,M为对话数
-
--
-\boldsymbol{H}=\left(\boldsymbol{u}_{1},..., \boldsymbol{u}_{T}\right)$$,T为Token数
-
-
--
-\boldsymbol{E}=\left(\boldsymbol{e}_{1},..., \boldsymbol{e}_{T}\right)$$,T为Token数
-
-
-- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
-
-
-
-
-
-
-- 双层反馈
-
-- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
-- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
-- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr + uΔc【计算损失时,给予正向或负向的反馈】
-
-
-
-
-- 双控读取器(模仿情感聊天机器ECM)
-
-- context-to-strategy:利用上下文信息来选择上下文相关的策略
-
--
-\boldsymbol{g}^{c} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
-
--
-\boldsymbol{g}^{o} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- 残差连接:在原始信息和更新信息之间进行权衡
-
--
-\begin{array}{r}
-
-
-
-h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
-\end{array}$$
-
-
-- 策略字典
-
-- 输入策略令牌的描述, 而不是策略令牌,以便模型对策略进行更深入的理解
-- Encoder-Decoder 之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
-- 响应生成
-
-- BlenderBot Decoder:$$\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}{<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}{y<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)$$
-
-
-- 联合训练
-
-- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
-
--
-\mathcal{L}_{1}=\left\{\begin{array}{ccc}
-
-
-
--\hat{o} \log \left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right) & \text { if } & \Delta s \leq 0
-\end{array}\right.\$$
-- 响应生成:标准交叉熵损失优化 cross-entropy
-
--
-
L2=−z=1∑Zlogp(yz∣y<z,ht′,V)
-
-
-
-
-
-
- Experiment
-
-- 采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
-
- Experimental Results
- Analyses
- conclusion
- 关注的问题
-
-- 预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
-- 建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
-
- 解决方法
-
-- 双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
-- 双层控制阅读器:策略到上下文流来生成策略约束响应
-
- 创新点 / 本文的优势
- 实验结论
- 有待提升的部分
+ Title: Feedback-Aware Double COntrolling Network for
+Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+双层反馈策略选择器:通过反馈信息预测策略
+双层控制阅读器:通过策略约束上下文响应
+策略词典:丰富策略的语义信息 ## Introduction ## Related Work ##
+Problem Formulation ## Approach
+上下文编码器
+
+- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
+
+双层反馈策略选择器
+
+- 策略选择
+
+- 输入
+
+- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
+- BlenderBot Encoder 编码策略S
+- EmoBERTa Encoder 编码上下文对话U
+
+- 公式
+
+- 上下文编码器(策略S同理):\[\boldsymbol{H}=\operatorname{Enc}_{cxt}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{H}=\left(\boldsymbol{u}_{1},...,
+\boldsymbol{u}_{T}\right)\],T为Token数
+
+- 情感编码器:\[\boldsymbol{E}=\operatorname{EmoBERTa}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{E}=\left(\boldsymbol{e}_{1},...,
+\boldsymbol{e}_{T}\right)\],T为Token数
+
+- 分类:\[\boldsymbol{o}=\operatorname{MLP}\left(\tanh
+\left(\boldsymbol{W}_{o}^{T}[\boldsymbol{s} ; \boldsymbol{c} ;
+\boldsymbol{r}]+\boldsymbol{b}_{\boldsymbol{o}}\right)\right)\]
+
+- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
+
+
+
+- 双层反馈
+
+- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
+- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
+- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr +
+uΔc【计算损失时,给予正向或负向的反馈】
+
+
+双控读取器(模仿情感聊天机器ECM)
+
+- context-to-strategy:利用上下文信息来选择上下文相关的策略
+
+- \[\boldsymbol{g}^{c} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{c}^{T} \boldsymbol{c} + \boldsymbol{b}_{c}
+\right)\]
+
+- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
+
+- \[\boldsymbol{g}^{o} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{o}^{T} \boldsymbol{o} + \boldsymbol{b}_{o}
+\right)\]
+
+- 残差连接:在原始信息和更新信息之间进行权衡
+
+- \[\begin{array}{r}
+o^{\prime}=(1-\beta) \cdot o+\beta \cdot g^{c} \otimes o \\
+h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
+\end{array}\]
+
+
+策略字典
+
+- 输入策略令牌的描述,
+而不是策略令牌,以便模型对策略进行更深入的理解
+- Encoder-Decoder
+之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC:
+A MIxed Strategy-Aware Model Integrating COMET for Emotional Support
+Conversation
+
+响应生成
+
+- BlenderBot Decoder:\[\boldsymbol{p}\left(y_{z} \mid
+\boldsymbol{y}_{<z}, \boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}_{y<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)\]
+
+联合训练
+
+- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
+
+- \[\mathcal{L}_{1}=\left\{\begin{array}{ccc}
+-\hat{o} \log
+\left(\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s>0 \\
+-\hat{o} \log
+\left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s \leq 0
+\end{array}\right.\\\]
+
+- 响应生成:标准交叉熵损失优化 cross-entropy
+
+- \[\mathcal{L}_{2}=-\sum_{z=1}^{Z} \log
+\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}_{<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)\]
+## Experiment
+
+
+采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
+## Experimental Results ## Analyses ## conclusion # 关注的问题
+
+
+预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
+建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
+# 解决方法
+双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
+双层控制阅读器:策略到上下文流来生成策略约束响应 # 创新点 /
+本文的优势
+
+实验结论
+有待提升的部分
@@ -483,7 +482,8 @@ true
+
+
diff --git a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
index ba9dd99..d96b209 100644
--- a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
+++ b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -141,7 +141,7 @@
-
+
@@ -254,142 +254,110 @@
- Title: A Knowledge Graph for Distress Management Conversations
-
- 论文速览
- Abstract
-
-- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
-- 提出HEAL知识图谱
-
-- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
-- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
-- 组成部分
-
-- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types
-- 104k Edge 连接:不同类型的节点之间的关系
-- 每个节点和41种情绪状态相关联
-
-
-
-
-
- Introduction
-
-- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
-- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
-- 相关工作
-
-- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
-
-
-- 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
-- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
-
-
-
- Related Work
-
-- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
-- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应
-
- Methodology
-
-- 数据集管理
-
-- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
-- 数据预处理
-
-
-- 概要
-
-- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
-
-
-- 凝聚聚类
-
-- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
-- 凝聚聚类法:递归地合并增加最小链接距离的簇对
-- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
-
-
-- 定义压力源
-
-- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
-- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
-
-
-- 期望、回复、反馈类型
-
-- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
-- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
-
-
-- 情感状态建模
-
-- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
-
-
-
- Statistical Analysis
-
-- HEAL知识图谱:2.2k集群节点和情感状态,104k连接
-- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
-
- Visualization and Interpretation
-
-- 表示大多数回答都是正向积极反馈
-
- Evaluating the Utility of HEAL in Responding to Distress Prompts
-
-- 获取共情响应
-
-- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
-- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
-
-
-- 自动评估
-
-- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
-- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
-
-
-- 人类评估【DOI: 10.18653/v1/d16-1230】
-
-- HEAL模型变现更好
-
-
-
- Discussion and Conclusion
-
-- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
-
-
- 关注的问题 / 本文的优势
-
-- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
-- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
-
- 解决方法 / 创新点
-
-- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
-- 统计和可视化分析,识别导致情绪强度降低的有利反应
-- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
-
- 实验结论
-
-- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
-- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
-- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
-
- 有待提升的部分
-
-- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
-- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
-- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
-
+ Title: A Knowledge Graph for Distress Management
+Conversations
+
+论文速览
+Abstract
+
+相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+
+- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
+- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
+- 组成部分
+
+- 22k Node 节点:识别不同类型的stressors, speaker expectations,
+responses, feedback types
+- 104k Edge 连接:不同类型的节点之间的关系
+- 每个节点和41种情绪状态相关联 ## Introduction
+
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+
+- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
+
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+
+- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
+- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
+## Related Work
+
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ##
+Methodology
+数据集管理
+
+- 采用reddit数据集,通过Pushshift
+API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
+- 数据预处理
+
+概要
+
+- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
+
+凝聚聚类
+
+- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
+- 凝聚聚类法:递归地合并增加最小链接距离的簇对
+- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
+
+定义压力源
+
+- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
+- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
+
+期望、回复、反馈类型
+
+- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
+- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
+
+情感状态建模
+
+- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
+## Statistical Analysis
+
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
+## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL
+in Responding to Distress Prompts
+获取共情响应
+
+- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
+- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
+
+自动评估
+
+- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
+- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
+
+人类评估【DOI: 10.18653/v1/d16-1230】
+
+- HEAL模型变现更好 ## Discussion and Conclusion
+
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
+关注的问题 / 本文的优势
+
+端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
+# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
+# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
+# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
@@ -478,7 +446,8 @@ true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Title: Feedback-Aware Double COntrolling Network for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 双层反馈策略选择器:通过反馈信息预测策略
-- 双层控制阅读器:通过策略约束上下文响应
-- 策略词典:丰富策略的语义信息
-
- Introduction
- Related Work
- Problem Formulation
- Approach
-
-- 上下文编码器
-
-- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
-
-
-- 双层反馈策略选择器
-
-- 策略选择
-
-- 输入
-
-- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
-- BlenderBot Encoder 编码策略S
-- EmoBERTa Encoder 编码上下文对话U
-
-
-- 公式
-
-- 上下文编码器(策略S同理):$$\boldsymbol{H}=\operatorname{Enc}{cxt}\left(\boldsymbol{[CLS]}, \boldsymbol{u}{1}, \boldsymbol{[SEP]}, \boldsymbol{u}{2}, …, \boldsymbol{u}{M}\right)$$,M为对话数
-
--
-\boldsymbol{H}=\left(\boldsymbol{u}_{1},..., \boldsymbol{u}_{T}\right)$$,T为Token数
-
-
--
-\boldsymbol{E}=\left(\boldsymbol{e}_{1},..., \boldsymbol{e}_{T}\right)$$,T为Token数
-
-
-- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
-
-
-
-
-
-
-- 双层反馈
-
-- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
-- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
-- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr + uΔc【计算损失时,给予正向或负向的反馈】
-
-
-
-
-- 双控读取器(模仿情感聊天机器ECM)
-
-- context-to-strategy:利用上下文信息来选择上下文相关的策略
-
--
-\boldsymbol{g}^{c} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
-
--
-\boldsymbol{g}^{o} = \operatorname{sigmoid}\left(
-
-
-
-\right)$$
-- 残差连接:在原始信息和更新信息之间进行权衡
-
--
-\begin{array}{r}
-
-
-
-h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
-\end{array}$$
-
-
-- 策略字典
-
-- 输入策略令牌的描述, 而不是策略令牌,以便模型对策略进行更深入的理解
-- Encoder-Decoder 之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
-- 响应生成
-
-- BlenderBot Decoder:$$\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}{<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}{y<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)$$
-
-
-- 联合训练
-
-- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
-
--
-\mathcal{L}_{1}=\left\{\begin{array}{ccc}
-
-
-
--\hat{o} \log \left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right) & \text { if } & \Delta s \leq 0
-\end{array}\right.\$$
-- 响应生成:标准交叉熵损失优化 cross-entropy
-
--
-
L2=−z=1∑Zlogp(yz∣y<z,ht′,V)
-
-
-
-
-
-
- Experiment
-
-- 采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
-
- Experimental Results
- Analyses
- conclusion
- 关注的问题
-
-- 预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
-- 建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
-
- 解决方法
-
-- 双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
-- 双层控制阅读器:策略到上下文流来生成策略约束响应
-
- 创新点 / 本文的优势
- 实验结论
- 有待提升的部分
+ Title: Feedback-Aware Double COntrolling Network for
+Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+双层反馈策略选择器:通过反馈信息预测策略
+双层控制阅读器:通过策略约束上下文响应
+策略词典:丰富策略的语义信息 ## Introduction ## Related Work ##
+Problem Formulation ## Approach
+上下文编码器
+
+- BlenderBot预训练编码器编码上下文历史对话U,得到Ht
+
+双层反馈策略选择器
+
+- 策略选择
+
+- 输入
+
+- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht
+- BlenderBot Encoder 编码策略S
+- EmoBERTa Encoder 编码上下文对话U
+
+- 公式
+
+- 上下文编码器(策略S同理):\[\boldsymbol{H}=\operatorname{Enc}_{cxt}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{H}=\left(\boldsymbol{u}_{1},...,
+\boldsymbol{u}_{T}\right)\],T为Token数
+
+- 情感编码器:\[\boldsymbol{E}=\operatorname{EmoBERTa}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+- \[\boldsymbol{E}=\left(\boldsymbol{e}_{1},...,
+\boldsymbol{e}_{T}\right)\],T为Token数
+
+- 分类:\[\boldsymbol{o}=\operatorname{MLP}\left(\tanh
+\left(\boldsymbol{W}_{o}^{T}[\boldsymbol{s} ; \boldsymbol{c} ;
+\boldsymbol{r}]+\boldsymbol{b}_{\boldsymbol{o}}\right)\right)\]
+
+- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到
+
+
+
+- 双层反馈
+
+- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr
+- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情
+- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr +
+uΔc【计算损失时,给予正向或负向的反馈】
+
+
+双控读取器(模仿情感聊天机器ECM)
+
+- context-to-strategy:利用上下文信息来选择上下文相关的策略
+
+- \[\boldsymbol{g}^{c} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{c}^{T} \boldsymbol{c} + \boldsymbol{b}_{c}
+\right)\]
+
+- strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
+
+- \[\boldsymbol{g}^{o} =
+\operatorname{sigmoid}\left(
+\boldsymbol{W}_{o}^{T} \boldsymbol{o} + \boldsymbol{b}_{o}
+\right)\]
+
+- 残差连接:在原始信息和更新信息之间进行权衡
+
+- \[\begin{array}{r}
+o^{\prime}=(1-\beta) \cdot o+\beta \cdot g^{c} \otimes o \\
+h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t}
+\end{array}\]
+
+
+策略字典
+
+- 输入策略令牌的描述,
+而不是策略令牌,以便模型对策略进行更深入的理解
+- Encoder-Decoder
+之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC:
+A MIxed Strategy-Aware Model Integrating COMET for Emotional Support
+Conversation
+
+响应生成
+
+- BlenderBot Decoder:\[\boldsymbol{p}\left(y_{z} \mid
+\boldsymbol{y}_{<z}, \boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}_{y<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime},
+\boldsymbol{V}\right)\]
+
+联合训练
+
+- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
+
+- \[\mathcal{L}_{1}=\left\{\begin{array}{ccc}
+-\hat{o} \log
+\left(\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s>0 \\
+-\hat{o} \log
+\left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right)
+& \text { if } & \Delta s \leq 0
+\end{array}\right.\\\]
+
+- 响应生成:标准交叉熵损失优化 cross-entropy
+
+- \[\mathcal{L}_{2}=-\sum_{z=1}^{Z} \log
+\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}_{<z},
+\boldsymbol{h}_{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)\]
+## Experiment
+
+
+采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得
+## Experimental Results ## Analyses ## conclusion # 关注的问题
+
+
+预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
+建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文
+# 解决方法
+双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
+双层控制阅读器:策略到上下文流来生成策略约束响应 # 创新点 /
+本文的优势
+
+实验结论
+有待提升的部分
@@ -483,7 +482,8 @@ true
+
+
diff --git a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
index ba9dd99..d96b209 100644
--- a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
+++ b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -141,7 +141,7 @@
-
+
@@ -254,142 +254,110 @@
- Title: A Knowledge Graph for Distress Management Conversations
-
- 论文速览
- Abstract
-
-- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
-- 提出HEAL知识图谱
-
-- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
-- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
-- 组成部分
-
-- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types
-- 104k Edge 连接:不同类型的节点之间的关系
-- 每个节点和41种情绪状态相关联
-
-
-
-
-
- Introduction
-
-- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
-- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
-- 相关工作
-
-- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
-
-
-- 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
-- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
-
-
-
- Related Work
-
-- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
-- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应
-
- Methodology
-
-- 数据集管理
-
-- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
-- 数据预处理
-
-
-- 概要
-
-- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
-
-
-- 凝聚聚类
-
-- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
-- 凝聚聚类法:递归地合并增加最小链接距离的簇对
-- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
-
-
-- 定义压力源
-
-- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
-- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
-
-
-- 期望、回复、反馈类型
-
-- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
-- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
-
-
-- 情感状态建模
-
-- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
-
-
-
- Statistical Analysis
-
-- HEAL知识图谱:2.2k集群节点和情感状态,104k连接
-- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
-
- Visualization and Interpretation
-
-- 表示大多数回答都是正向积极反馈
-
- Evaluating the Utility of HEAL in Responding to Distress Prompts
-
-- 获取共情响应
-
-- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
-- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
-
-
-- 自动评估
-
-- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
-- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
-
-
-- 人类评估【DOI: 10.18653/v1/d16-1230】
-
-- HEAL模型变现更好
-
-
-
- Discussion and Conclusion
-
-- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
-
-
- 关注的问题 / 本文的优势
-
-- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
-- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
-
- 解决方法 / 创新点
-
-- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
-- 统计和可视化分析,识别导致情绪强度降低的有利反应
-- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
-
- 实验结论
-
-- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
-- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
-- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
-
- 有待提升的部分
-
-- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
-- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
-- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
-
+ Title: A Knowledge Graph for Distress Management
+Conversations
+
+论文速览
+Abstract
+
+相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+
+- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
+- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
+- 组成部分
+
+- 22k Node 节点:识别不同类型的stressors, speaker expectations,
+responses, feedback types
+- 104k Edge 连接:不同类型的节点之间的关系
+- 每个节点和41种情绪状态相关联 ## Introduction
+
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+
+- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
+
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+
+- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
+- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
+## Related Work
+
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ##
+Methodology
+数据集管理
+
+- 采用reddit数据集,通过Pushshift
+API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
+- 数据预处理
+
+概要
+
+- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
+
+凝聚聚类
+
+- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
+- 凝聚聚类法:递归地合并增加最小链接距离的簇对
+- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
+
+定义压力源
+
+- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
+- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
+
+期望、回复、反馈类型
+
+- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
+- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
+
+情感状态建模
+
+- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
+## Statistical Analysis
+
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
+## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL
+in Responding to Distress Prompts
+获取共情响应
+
+- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
+- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
+
+自动评估
+
+- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
+- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
+
+人类评估【DOI: 10.18653/v1/d16-1230】
+
+- HEAL模型变现更好 ## Discussion and Conclusion
+
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
+关注的问题 / 本文的优势
+
+端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
+# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
+# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
+# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
@@ -478,7 +446,8 @@ true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: Feedback-Aware Double COntrolling Network for Emotional Support Conversation
-
论文速览
-Abstract
--
-
- 双层反馈策略选择器:通过反馈信息预测策略 -
- 双层控制阅读器:通过策略约束上下文响应 -
- 策略词典:丰富策略的语义信息 -
Introduction
-Related Work
-Problem Formulation
-Approach
--
-
- 上下文编码器
-
-
-
- BlenderBot预训练编码器编码上下文历史对话U,得到Ht -
- - 双层反馈策略选择器
-
-
-
- 策略选择
-
-
-
- 输入
-
-
-
- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht -
- BlenderBot Encoder 编码策略S -
- EmoBERTa Encoder 编码上下文对话U -
- - 公式
-
-
-
- 上下文编码器(策略S同理):$$\boldsymbol{H}=\operatorname{Enc}{cxt}\left(\boldsymbol{[CLS]}, \boldsymbol{u}{1}, \boldsymbol{[SEP]}, \boldsymbol{u}{2}, …, \boldsymbol{u}{M}\right)$$,M为对话数
-
-
-
- -\boldsymbol{H}=\left(\boldsymbol{u}_{1},..., \boldsymbol{u}_{T}\right)$$,T为Token数 - - -
- -\boldsymbol{E}=\left(\boldsymbol{e}_{1},..., \boldsymbol{e}_{T}\right)$$,T为Token数 - - -
- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到 -
-
- - 上下文编码器(策略S同理):$$\boldsymbol{H}=\operatorname{Enc}{cxt}\left(\boldsymbol{[CLS]}, \boldsymbol{u}{1}, \boldsymbol{[SEP]}, \boldsymbol{u}{2}, …, \boldsymbol{u}{M}\right)$$,M为对话数
-
- - 输入
-
- 双层反馈
-
-
-
- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr -
- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情 -
- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr + uΔc【计算损失时,给予正向或负向的反馈】 -
-
- - 策略选择
-
- 双控读取器(模仿情感聊天机器ECM)
-
-
-
- context-to-strategy:利用上下文信息来选择上下文相关的策略
-
-
-
- -\boldsymbol{g}^{c} = \operatorname{sigmoid}\left( - - -
- - strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
-
-
-
- -\boldsymbol{g}^{o} = \operatorname{sigmoid}\left( - - -
- - 残差连接:在原始信息和更新信息之间进行权衡
-
-
-
- -\begin{array}{r} - - -
-\end{array}$$
-
- - context-to-strategy:利用上下文信息来选择上下文相关的策略
-
- 策略字典
-
-
-
- 输入策略令牌的描述, 而不是策略令牌,以便模型对策略进行更深入的理解 -
- Encoder-Decoder 之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation -
- - 响应生成
-
-
-
- BlenderBot Decoder:$$\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}{<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}{y<z}, \boldsymbol{h}{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)$$ -
- - 联合训练
-
-
-
- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
-
-
-
- -\mathcal{L}_{1}=\left\{\begin{array}{ccc} - - -
-\end{array}\right.\$$
- - 响应生成:标准交叉熵损失优化 cross-entropy
-
-
-
-
-
L2=−z=1∑Zlogp(yz∣y<z,ht′,V)
-
-
- -
-
- - 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
-
Experiment
--
-
- 采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得 -
Experimental Results
-Analyses
-conclusion
-关注的问题
--
-
- 预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关 -
- 建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文 -
解决方法
--
-
- 双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略 -
- 双层控制阅读器:策略到上下文流来生成策略约束响应 -
创新点 / 本文的优势
-实验结论
-有待提升的部分
+Title: Feedback-Aware Double COntrolling Network for +Emotional Support Conversation
+
论文速览
+Abstract
+-
+
双层反馈策略选择器:通过反馈信息预测策略
+双层控制阅读器:通过策略约束上下文响应
+策略词典:丰富策略的语义信息 ## Introduction ## Related Work ## +Problem Formulation ## Approach
+上下文编码器
+-
+
- BlenderBot预训练编码器编码上下文历史对话U,得到Ht +
+双层反馈策略选择器
+-
+
- 策略选择
+
-
+
- 输入
+
-
+
- BlenderBot Encoder 编码上下文历史对话U,得到隐状态Ht +
- BlenderBot Encoder 编码策略S +
- EmoBERTa Encoder 编码上下文对话U +
+ - 公式
+
-
+
- 上下文编码器(策略S同理):\[\boldsymbol{H}=\operatorname{Enc}_{cxt}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
-
+
- \[\boldsymbol{H}=\left(\boldsymbol{u}_{1},..., +\boldsymbol{u}_{T}\right)\],T为Token数 +
+ - 情感编码器:\[\boldsymbol{E}=\operatorname{EmoBERTa}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
-
+
- \[\boldsymbol{E}=\left(\boldsymbol{e}_{1},..., +\boldsymbol{e}_{T}\right)\],T为Token数 +
+ - 分类:\[\boldsymbol{o}=\operatorname{MLP}\left(\tanh
+\left(\boldsymbol{W}_{o}^{T}[\boldsymbol{s} ; \boldsymbol{c} ;
+\boldsymbol{r}]+\boldsymbol{b}_{\boldsymbol{o}}\right)\right)\]
+
-
+
- s、c、r 为策略S、上下文H、情感分类E。编码+平均池化操作后得到 +
+
+ - 上下文编码器(策略S同理):\[\boldsymbol{H}=\operatorname{Enc}_{cxt}\left(\boldsymbol{[CLS]},
+\boldsymbol{u}_{1}, \boldsymbol{[SEP]}, \boldsymbol{u}_{2}, ...,
+\boldsymbol{u}_{M}\right)\],M为对话数
+
+ - 输入
+
- 双层反馈
+
-
+
- 回合级反馈:局部变量,当前用户的感受。包含每轮对话Seeker情感Δe和Seeker评分变化Δr +
- 对话级反馈:全局变量Δc,用户的全局状态。包含Seeker在谈话后的情绪压力、Supporter对话题的回应的相关性、Supporter对Seeker感受的理解和共情 +
- 融合adapter:整合回合级和会话级反馈的两类语义信息。Δs = Δe + Δr + +uΔc【计算损失时,给予正向或负向的反馈】 +
+
+- 策略选择
+
双控读取器(模仿情感聊天机器ECM)
+-
+
- context-to-strategy:利用上下文信息来选择上下文相关的策略
+
-
+
- \[\boldsymbol{g}^{c} = +\operatorname{sigmoid}\left( +\boldsymbol{W}_{c}^{T} \boldsymbol{c} + \boldsymbol{b}_{c} +\right)\] +
+ - strategy-to-context:编码阶段可以关注与策略相关的上下文,从而生成策略约束的响应
+
-
+
- \[\boldsymbol{g}^{o} = +\operatorname{sigmoid}\left( +\boldsymbol{W}_{o}^{T} \boldsymbol{o} + \boldsymbol{b}_{o} +\right)\] +
+ - 残差连接:在原始信息和更新信息之间进行权衡
+
-
+
- \[\begin{array}{r} +o^{\prime}=(1-\beta) \cdot o+\beta \cdot g^{c} \otimes o \\ +h_{t}^{\prime}=(1-\alpha) \cdot h_{t}+\alpha \cdot g^{o} \otimes h_{t} +\end{array}\] +
+
+- context-to-strategy:利用上下文信息来选择上下文相关的策略
+
策略字典
+-
+
- 输入策略令牌的描述, +而不是策略令牌,以便模型对策略进行更深入的理解 +
- Encoder-Decoder +之间的状态传输类似于MISC,采用cross-attention代替self-attentionMISC: +A MIxed Strategy-Aware Model Integrating COMET for Emotional Support +Conversation +
+响应生成
+-
+
- BlenderBot Decoder:\[\boldsymbol{p}\left(y_{z} \mid +\boldsymbol{y}_{<z}, \boldsymbol{h}_{\boldsymbol{t}}^{\prime}, +\boldsymbol{V}\right)=\text { Generator }\left(\boldsymbol{W}_{y<z}, +\boldsymbol{h}_{\boldsymbol{t}}^{\prime}, +\boldsymbol{V}\right)\] +
+联合训练
+-
+
- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
+
-
+
- \[\mathcal{L}_{1}=\left\{\begin{array}{ccc} +-\hat{o} \log +\left(\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right) +& \text { if } & \Delta s>0 \\ +-\hat{o} \log +\left(1-\operatorname{softmax}\left(\boldsymbol{o}^{\prime}\right)\right) +& \text { if } & \Delta s \leq 0 +\end{array}\right.\\\] +
+ - 响应生成:标准交叉熵损失优化 cross-entropy
+
-
+
- \[\mathcal{L}_{2}=-\sum_{z=1}^{Z} \log +\boldsymbol{p}\left(y_{z} \mid \boldsymbol{y}_{<z}, +\boldsymbol{h}_{\boldsymbol{t}}^{\prime}, \boldsymbol{V}\right)\] +## Experiment +
+
+- 策略预测:反馈感知负对数似然 feedback-aware negative log-likelihood
+
采用EmoBERTa-base作为特征提取器,以获取Seeker的情感得分和情感表征,情感得分由softmax函数使用EmoBERTa-base的[CLS]表示获得 +## Experimental Results ## Analyses ## conclusion # 关注的问题
+
-
+
预测策略只依靠对话历史,而不考虑求助者反馈,导致预测的结果与用户无关
+建模过程只关注上下文到策略,而不关注策略到上下文和与策略相关的上下文 +# 解决方法
+双层反馈策略选择器:利用回合级和会话级反馈信息来激励或惩罚策略
+双层控制阅读器:策略到上下文流来生成策略约束响应 # 创新点 / +本文的优势
+
实验结论
+有待提升的部分
true
+
+
diff --git a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
index ba9dd99..d96b209 100644
--- a/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
+++ b/2023/HEAL_ A Knowledge Graph for Distress Management Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -141,7 +141,7 @@
-
+
@@ -254,142 +254,110 @@
- Title: A Knowledge Graph for Distress Management Conversations
-
- 论文速览
- Abstract
-
-- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
-- 提出HEAL知识图谱
-
-- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
-- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
-- 组成部分
-
-- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types
-- 104k Edge 连接:不同类型的节点之间的关系
-- 每个节点和41种情绪状态相关联
-
-
-
-
-
- Introduction
-
-- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
-- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
-- 相关工作
-
-- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
-
-
-- 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
-- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
-
-
-
- Related Work
-
-- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
-- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应
-
- Methodology
-
-- 数据集管理
-
-- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
-- 数据预处理
-
-
-- 概要
-
-- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
-
-
-- 凝聚聚类
-
-- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
-- 凝聚聚类法:递归地合并增加最小链接距离的簇对
-- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
-
-
-- 定义压力源
-
-- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
-- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
-
-
-- 期望、回复、反馈类型
-
-- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
-- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
-
-
-- 情感状态建模
-
-- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
-
-
-
- Statistical Analysis
-
-- HEAL知识图谱:2.2k集群节点和情感状态,104k连接
-- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
-
- Visualization and Interpretation
-
-- 表示大多数回答都是正向积极反馈
-
- Evaluating the Utility of HEAL in Responding to Distress Prompts
-
-- 获取共情响应
-
-- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
-- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
-
-
-- 自动评估
-
-- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
-- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
-
-
-- 人类评估【DOI: 10.18653/v1/d16-1230】
-
-- HEAL模型变现更好
-
-
-
- Discussion and Conclusion
-
-- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
-
-
- 关注的问题 / 本文的优势
-
-- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
-- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
-
- 解决方法 / 创新点
-
-- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
-- 统计和可视化分析,识别导致情绪强度降低的有利反应
-- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
-
- 实验结论
-
-- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
-- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
-- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
-
- 有待提升的部分
-
-- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
-- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
-- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
-
+ Title: A Knowledge Graph for Distress Management
+Conversations
+
+论文速览
+Abstract
+
+相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+
+- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
+- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
+- 组成部分
+
+- 22k Node 节点:识别不同类型的stressors, speaker expectations,
+responses, feedback types
+- 104k Edge 连接:不同类型的节点之间的关系
+- 每个节点和41种情绪状态相关联 ## Introduction
+
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+
+- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
+
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+
+- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
+- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
+## Related Work
+
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ##
+Methodology
+数据集管理
+
+- 采用reddit数据集,通过Pushshift
+API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
+- 数据预处理
+
+概要
+
+- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
+
+凝聚聚类
+
+- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
+- 凝聚聚类法:递归地合并增加最小链接距离的簇对
+- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
+
+定义压力源
+
+- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
+- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
+
+期望、回复、反馈类型
+
+- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
+- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
+
+情感状态建模
+
+- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
+## Statistical Analysis
+
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
+## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL
+in Responding to Distress Prompts
+获取共情响应
+
+- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
+- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
+
+自动评估
+
+- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
+- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
+
+人类评估【DOI: 10.18653/v1/d16-1230】
+
+- HEAL模型变现更好 ## Discussion and Conclusion
+
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
+关注的问题 / 本文的优势
+
+端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
+# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
+# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
+# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
@@ -478,7 +446,8 @@ true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Title: A Knowledge Graph for Distress Management Conversations
-
- 论文速览
- Abstract
-
-- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
-- 提出HEAL知识图谱
-
-- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
-- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
-- 组成部分
-
-- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types
-- 104k Edge 连接:不同类型的节点之间的关系
-- 每个节点和41种情绪状态相关联
-
-
-
-
-
- Introduction
-
-- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
-- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
-- 相关工作
-
-- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
-
-
-- 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
-- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
-
-
-
- Related Work
-
-- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
-- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应
-
- Methodology
-
-- 数据集管理
-
-- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
-- 数据预处理
-
-
-- 概要
-
-- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
-
-
-- 凝聚聚类
-
-- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
-- 凝聚聚类法:递归地合并增加最小链接距离的簇对
-- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
-
-
-- 定义压力源
-
-- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
-- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
-
-
-- 期望、回复、反馈类型
-
-- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
-- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
-
-
-- 情感状态建模
-
-- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
-
-
-
- Statistical Analysis
-
-- HEAL知识图谱:2.2k集群节点和情感状态,104k连接
-- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
-
- Visualization and Interpretation
-
-- 表示大多数回答都是正向积极反馈
-
- Evaluating the Utility of HEAL in Responding to Distress Prompts
-
-- 获取共情响应
-
-- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
-- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
-
-
-- 自动评估
-
-- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
-- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
-
-
-- 人类评估【DOI: 10.18653/v1/d16-1230】
-
-- HEAL模型变现更好
-
-
-
- Discussion and Conclusion
-
-- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
-
-
- 关注的问题 / 本文的优势
-
-- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
-- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
-
- 解决方法 / 创新点
-
-- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
-- 统计和可视化分析,识别导致情绪强度降低的有利反应
-- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
-
- 实验结论
-
-- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
-- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
-- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
-
- 有待提升的部分
-
-- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
-- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
-- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
-
+ Title: A Knowledge Graph for Distress Management
+Conversations
+
+论文速览
+Abstract
+
+相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+
+- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱
+- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法
+- 组成部分
+
+- 22k Node 节点:识别不同类型的stressors, speaker expectations,
+responses, feedback types
+- 104k Edge 连接:不同类型的节点之间的关系
+- 每个节点和41种情绪状态相关联 ## Introduction
+
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+
+- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话
+
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+
+- 五类节点:压力源、期望、回应类型、反馈类型、情感状态
+- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应
+## Related Work
+
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ##
+Methodology
+数据集管理
+
+- 采用reddit数据集,通过Pushshift
+API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp
+- 数据预处理
+
+概要
+
+- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质
+
+凝聚聚类
+
+- 自动聚类:区分对话中的压力源、期望、响应和反馈类型
+- 凝聚聚类法:递归地合并增加最小链接距离的簇对
+- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算
+
+定义压力源
+
+- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。
+- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。
+
+期望、回复、反馈类型
+
+- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。
+- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。
+
+情感状态建模
+
+- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。
+## Statistical Analysis
+
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应
+## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL
+in Responding to Distress Prompts
+获取共情响应
+
+- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话
+- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应
+
+自动评估
+
+- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应
+- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳
+
+人类评估【DOI: 10.18653/v1/d16-1230】
+
+- HEAL模型变现更好 ## Discussion and Conclusion
+
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
+关注的问题 / 本文的优势
+
+端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。
+# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性
+# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应
+# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
@@ -478,7 +446,8 @@ true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: A Knowledge Graph for Distress Management Conversations
- -论文速览
-Abstract
--
-
- 相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案 -
- 提出HEAL知识图谱
-
-
-
- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱 -
- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法 -
- 组成部分
-
-
-
- 22k Node 节点:识别不同类型的stressors, speaker expectations, responses, feedback types -
- 104k Edge 连接:不同类型的节点之间的关系 -
- 每个节点和41种情绪状态相关联 -
-
-
Introduction
--
-
- 神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠 -
- 使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应 -
- 相关工作
-
-
-
- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话 -
- - 本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
-
-
-
- 五类节点:压力源、期望、回应类型、反馈类型、情感状态 -
- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应 -
-
Related Work
--
-
- 知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识 -
- 目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 -
Methodology
--
-
- 数据集管理
-
-
-
- 采用reddit数据集,通过Pushshift API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp -
- 数据预处理 -
- - 概要
-
-
-
- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质 -
- - 凝聚聚类
-
-
-
- 自动聚类:区分对话中的压力源、期望、响应和反馈类型 -
- 凝聚聚类法:递归地合并增加最小链接距离的簇对 -
- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算 -
- - 定义压力源
-
-
-
- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。 -
- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。 -
- - 期望、回复、反馈类型
-
-
-
- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。 -
- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。 -
- - 情感状态建模
-
-
-
- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。 -
-
Statistical Analysis
--
-
- HEAL知识图谱:2.2k集群节点和情感状态,104k连接 -
- 反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应 -
Visualization and Interpretation
--
-
- 表示大多数回答都是正向积极反馈 -
Evaluating the Utility of HEAL in Responding to Distress Prompts
--
-
- 获取共情响应
-
-
-
- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话 -
- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应 -
- - 自动评估
-
-
-
- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应 -
- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳 -
- - 人类评估【DOI: 10.18653/v1/d16-1230】
-
-
-
- HEAL模型变现更好 -
-
Discussion and Conclusion
--
-
- HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来 - -
关注的问题 / 本文的优势
--
-
- 端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。 -
- 目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。 -
解决方法 / 创新点
--
-
- 开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态 -
- 统计和可视化分析,识别导致情绪强度降低的有利反应 -
- 评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性 -
实验结论
--
-
- 与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应 -
- 统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态 -
- 使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应 -
有待提升的部分
--
-
- 只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发 -
- 知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性 -
- 仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望 -
Title: A Knowledge Graph for Distress Management +Conversations
+ +论文速览
+Abstract
+-
+
相比于seq2seq的不确定性,聊天机器人利用知识图谱进行推理,被视为端到端模型的高效、万无一失的解决方案
+提出HEAL知识图谱
+-
+
- 基于1M痛苦叙述及其相应的安慰回应而开发的知识图谱 +
- 图谱可视化:表现了对话双方的情绪动态和帮助缓解情绪的有效方法 +
- 组成部分
+
-
+
- 22k Node 节点:识别不同类型的stressors, speaker expectations, +responses, feedback types +
- 104k Edge 连接:不同类型的节点之间的关系 +
- 每个节点和41种情绪状态相关联 ## Introduction +
+
+神经网络架构模型缺乏可控性和黑箱性质,导致其并不可靠
+使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应
+相关工作
+-
+
- ConceptNet、ATOMIC主要是通过捕获事实知识,在开放对话中嵌入常识推理辅助对话,不适用于移情对话 +
+本文,通过子Reddit精心选择的对压力事件叙述和回应,生成了一个压力对话管理知识图谱HEAL
+-
+
- 五类节点:压力源、期望、回应类型、反馈类型、情感状态 +
- 可以准确描述以痛苦为导向对话的潜在背景,使对话模型可以检索到更具体的上下文响应。提取响应会导致的反馈类型和是否能达到期望等信息,从而产生更为合适的反应 +## Related Work +
+知识图谱可以帮助NLP理解用户的输入,拓展用户输入中的事实和常识性知识
+目前工作关注于知识感知和推理对话,不会捕捉情感推理和移情反应 ## +Methodology
+数据集管理
+-
+
- 采用reddit数据集,通过Pushshift +API,收集和处理8个子reddit对话主题:mentalhealthsupport、offmychest、sad、anxietyhelp、depression、suicidewatch、depressed、depressionhelp +
- 数据预处理 +
+概要
+-
+
- 针对过长而超出预训练语言模型输入上限的对话,本文采用SMMRY摘要算法保留叙事本质 +
+凝聚聚类
+-
+
- 自动聚类:区分对话中的压力源、期望、响应和反馈类型 +
- 凝聚聚类法:递归地合并增加最小链接距离的簇对 +
- 链接距离:对SentenceBERT生成的embedding使用余弦相似度计算 +
+定义压力源
+-
+
- 每个阈值计算了各种聚类质量指标,结果显示以0.85的相似度阈值区分压力源最合适,将压力源中的4.7%分为了4363个类。 +
- 将聚类结果按照TF-IDF建模,可以明显区分压力源,表明聚类结果的可靠性。 +
+期望、回复、反馈类型
+-
+
- 提取带有❓的句子作为问题,以此问题提取相关的响应和反馈。使用NLTK分离响应和反馈中的单个对话,方便后续对其进行单一种类的聚类。 +
- 聚类方法与压力源一致,每个集群至少有两个不同的集群元素。 +
+情感状态建模
+-
+
- 使用Pu提出的基于BERT的情感分类器,将每一个簇与某一情感状态相关联,共有41种情感状态。先将每一个簇下的每个文本进行分类,再按照情感出现次数和分类置信度排序,选取最相关的情感状态。 +## Statistical Analysis +
+HEAL知识图谱:2.2k集群节点和情感状态,104k连接
+反馈集群中,负面情绪明显减少,证明HEAL中存在帮助人们降低负面情感状态的有用响应 +## Visualization and Interpretation
+表示大多数回答都是正向积极反馈 ## Evaluating the Utility of HEAL +in Responding to Distress Prompts
+获取共情响应
+-
+
- 从测试集中选取和压力源中现有叙述相似性高于0.75的新对话 +
- 根据压力源和响应之间边权的权重、响应簇大小进行排序,选择排名高的响应 +
+自动评估
+-
+
- HEAL的响应更加多样化,可以根据给定的情况给出特定的响应 +
- 在其他自动指标BLEU、METEOR和ROUGE方面表现不佳 +
+人类评估【DOI: 10.18653/v1/d16-1230】
+-
+
- HEAL模型变现更好 ## Discussion and Conclusion +
+HEAL:利用Reddit上约1M个与痛苦相关的对话得出的知识图谱。在不同类型的压力源、说话者期望、求助者反应和求助者反馈类型之间形成联系,同时将每个节点与41种情感状态中的一种联系起来
+
+
关注的问题 / 本文的优势
+-
+
端到端对话经常会产生通用和重复性对话,缺乏可控性。使用常识推理和知识图结构表示,可以生成适合的、可预测的、多策略的回应。
+目前的知识图谱不适用于移情对话。移情领域缺乏数据集和模型帮助产生移情反应,还缺乏具有上下文-相应之间关系的知识图谱。 +# 解决方法 / 创新点
+开发大规模知识图谱HEAL,识别不同的压力源、期望、响应、反馈和该对话的情感状态
+统计和可视化分析,识别导致情绪强度降低的有利反应
+评估通过HEAL检索到的回应,在解决情感困扰问题上的共情性、多样性、可靠性 +# 实验结论
+与RoBERTa、Blender进行比较,HEAL能够产生更多样化、更移情的反应
+统计和可视化分析证实了在HEAL中存在有用的反应策略,这些策略降低了遭受痛苦的人的负面情感状态
+使用纯生成模型来解决痛苦存在危险,HEAL通过战略性地识别与给定提示相关的特定压力源来避免不适当的反应 +# 有待提升的部分
+只使用了压力源与回复的边缘权重,进一步可以通过将边缘权重与说话者的期望和反馈结合起来来开发
+知识图的信息可以用于增强神经反应生成模型,并为这些模型引入更多的可控性和可解释性,从而提高可靠性
+仅限于识别≈4K的压力源,可以从网络上获取更多数据来增强知识图谱,这将帮助其能够处理更大范围的压力源和期望
+
true
+
+
diff --git a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
index 4770655..9756923 100644
--- a/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
+++ b/2023/Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,311 +255,247 @@
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
-
- 论文速览
- Abstract
-
-- 混和主动性:按照说话者角色和主动类型分为四类
-- 提出四个情绪支持指标
-- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI)
-
- Introduction
-
-- ESC系统
-
-- 在适当的时候发起讨论,目的是提出建议,并解决问题
-
-
-- 相关工作
-
-- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息
-- 情感推理用来生成共情反应
-- identifying the dialogue acts of the utterances
-- ESC 系统预测下一个对话策略
-
-
-- ESC问题的三个挑战
-
-- 系统应该在对话过程中何时采取主动?
-- 系统发起子对话需要什么样的信息?
-- 系统如何促进混合主动交互?
-
-
-- 解决方法
-
-- 策略预测:确定下一回合混合主动策略
-- 知识选择:收集下一回合的必要知识
-- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
-
-
-- 提出的新东西
-
-- 混合主动性特征
-
-- EAFR模式:话语注释为不同类型的说话者角色和主动类型
-- Expression, Action, Reflection, Feedback
-
-
-- 情感支持指标
-
-- Proactivity, Information, Repetition, Relaxation
-
-
-- KEMI
-
-- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
-- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
-
-
-
-
-- 主要贡献
-
-- EAFR 注释模式和四种情感支持指标
-- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
-
-
-
- Related Works
-
-- ESC
-
-- 检测用户情绪
-- 将情感信号放入Respond中
-- 情绪感知反应,情感风格转移
-- 共情对话系统
-
-- 情感推理技巧
-- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
-
-
-
-
-- 混合主动对话
-
- Preliminary Analysis
-
-- EAFR
-
-- 四种注释方法:按照角色和主动类型区分
-- 四种评价指标:【待看】
-
-
-- 混合主动性分析
-- 混和主动性的挑战
-
-- 系统何时采取主动?
-- 系统发起子对话时,需要什么信息?
-
-- 情感识别:识别用户情感状态
-- 因果识别:导致情感状态的压力源
-- 认知识别:解决问题的过程
-
-
-- 根据历史对话,系统自发判断响应的主动或被动
-
-
-- 问题定义
-
-- 给定历史对话C和用户情况s,产生相应r
-
-- 策略预测y,细粒度主动性
-- 知识选择k
-- 使用y和k生成混合主动相应r
-
-
-
-
-
- Method
-
-- 知识获取
-
-- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-- COMET常识性知识扩展查询:Cp = COMET(p, ut)
-- 构造查询图:û = {ut, {Cp}}
-
-- expectation:ut
-- affective:[xReact]
-- stressor:[xIntent]
-- responses:[xWant] [xNeed] [xEffect]
-
-
-- 子图检索
-
-- 相似度计算:sentence-BERT
-- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
-- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
-
-
-
-
-
-
-- 混合主动响应生成
-
-- 使用基于上下文的编码器,编码上下文对话C和知识K
-- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
-- 优化损失函数,最大化负对数似然函数L
-
-
-
- Experiment
-
-- 实验基础
-
-- 数据集:ESConv、MI
-- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L)
-
-
-- 总体表现
-
-- BlenderBot优于Transformer
-- GLHG、MISI有效地利用了常识性知识
-- 基于策略的联合学习可以提高性能
-- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
-
-
-- 人工评价
-
-- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
-
-
-- 消融实验
-
-- HEAL可以有效提升策略预测准确度
-- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
-- 认知识别是最有效的
-- 对比Oracle,还有很大的提升空间
-
-
-- 混和主动性分析
-
-- 情感支持指标分析
-
-- KEMI有效的平衡了主动性和非主动性回复
-- KEMI回复的信息更加丰富
-- KEMI容易生成重复性回复
-- KEMI有效地帮助用户解决情绪问题
-
-
-- 会话进度
-
-- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
-- KEMI在对话中后期更能主动相应并缓解用户负面情绪
-
-
-
-
-- 案例分析
-
- Conclusions
-
-- 首次提出ESC中混和主动性的特点,并阐述其重要性
-- KEMI框架
-
-- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
-- 通过检索到的知识,进行策略预测和响应生成的多任务学习
-
-
-- 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
-
- Limitations
-
-- 评价指标有待改进
-- 没有考虑不同知识检索方法的不同
-- 从复杂的KG图中检索知识的方法有待提高
-- 某些应用的知识图难以获取
-- 知识库的建立需要具有专业知识的人员
-
- Appendix
-
-- 混和主动性
-
-- 对话主动性分析
-
-- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
-- 情绪强度预测模型:根据用户话语预测负面情绪强度
-- 用户模拟并注释四种评价指标 :【待看】
-
-
-- 对话流分析
-
-- ESC在对话中充当主动角色;ED在对话中充当被动角色
-
-
-- 对话过程
-
-- 研究内容:主动性和情绪强度变化的关系
-- 结论
-
-- 交互时间很重要
-- 情绪缓解后才更有利于解决问题
-
-
-
-
-- ES指标
-
-
-- COMET
-
-- 常识性关系
-
-
-- HEAL
-
-- 情绪压力和安慰回应之间的知识图谱
-- 表现了对话双方的情绪动态,确定缓解情绪的方法
-
-
-
- 解决了什么问题
-
-- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
-
- 怎么解决的 / 该方法的优势
-
-- 常识知识生成器 COMET:
-- 常识性知识获取 HEAL:
-
- 有什么创新点
-
-- 提出ESC知识增强混合主动框架
-
-- 人类和系统都可以主动引导交互方向
-- 通过子图检索从心理健康知识图谱中检索外部知识
-
-
-- 新的分析方法
-
-
-保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-- 按照说话者角色和主动类型将话语注释为不同类型
-
-- Expression:用户主动
-- Action:系统主动
-- Feedback:用户非主动
-- Reflection:系统非主动
-
-
-- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-- Proactivity:系统主动的对话占系统对话的比例
-- Information:系统首次提出的频繁词占比
-- Repetition:系统重复用户提出的术语的频次占比
-- Relaxation:情绪强度的改善
-
-
-
- 实验结果好在哪里,怎么证明的
- 相关工作分析
- 可以提升的地方
+ Title: Knowledge-enhanced Mixed-initiative Dialogue
+System for Emotional Support Conversations
+
+
+论文速览
+Abstract
+
+混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ##
+Introduction
+ESC系统
+
+- 在适当的时候发起讨论,目的是提出建议,并解决问题
+
+相关工作
+
+- CIS(conversational
+information-seeking)可以主动发起对话,澄清交互并探索更多的信息
+- 情感推理用来生成共情反应
+- identifying the dialogue acts of the utterances
+- ESC 系统预测下一个对话策略
+
+ESC问题的三个挑战
+
+- 系统应该在对话过程中何时采取主动?
+- 系统发起子对话需要什么样的信息?
+- 系统如何促进混合主动交互?
+
+解决方法
+
+- 策略预测:确定下一回合混合主动策略
+- 知识选择:收集下一回合的必要知识
+- 响应生成:在适当的混合主动策略和知识下产生情感支持响应
+
+提出的新东西
+
+- 混合主动性特征
+
+- EAFR模式:话语注释为不同类型的说话者角色和主动类型
+- Expression, Action, Reflection, Feedback
+
+- 情感支持指标
+
+- Proactivity, Information, Repetition, Relaxation
+
+- KEMI
+
+- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索
+- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应
+
+
+主要贡献
+
+- EAFR 注释模式和四种情感支持指标
+- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识
+## Related Works
+
+ESC
+
+- 检测用户情绪
+- 将情感信号放入Respond中
+- 情绪感知反应,情感风格转移
+- 共情对话系统
+
+- 情感推理技巧
+- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识
+
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+
+- 四种注释方法:按照角色和主动类型区分
+- 四种评价指标:【待看】
+
+混合主动性分析
+混和主动性的挑战
+
+- 系统何时采取主动?
+- 系统发起子对话时,需要什么信息?
+
+- 情感识别:识别用户情感状态
+- 因果识别:导致情感状态的压力源
+- 认知识别:解决问题的过程
+
+- 根据历史对话,系统自发判断响应的主动或被动
+
+问题定义
+
+- 给定历史对话C和用户情况s,产生相应r
+
+- 策略预测y,细粒度主动性
+- 知识选择k
+- 使用y和k生成混合主动相应r ## Method
+
+
+知识获取
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
+- COMET常识性知识扩展查询:Cp = COMET(p, ut)
+- 构造查询图:û = {ut, {Cp}}
+
+- expectation:ut
+- affective:[xReact]
+- stressor:[xIntent]
+- responses:[xWant] [xNeed] [xEffect]
+
+- 子图检索
+
+- 相似度计算:sentence-BERT
+- 针对每个 ût
+中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图
+- 针对每个 E
+中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K
+
+
+
+混合主动响应生成
+
+- 使用基于上下文的编码器,编码上下文对话C和知识K
+- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+- 优化损失函数,最大化负对数似然函数L ## Experiment
+
+实验基础
+
+- 数据集:ESConv、MI
+- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n
+(B-n)、内容保留度ROUGE-L (R-L)
+
+总体表现
+
+- BlenderBot优于Transformer
+- GLHG、MISI有效地利用了常识性知识
+- 基于策略的联合学习可以提高性能
+- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖
+
+人工评价
+
+- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜
+
+消融实验
+
+- HEAL可以有效提升策略预测准确度
+- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确
+- 认知识别是最有效的
+- 对比Oracle,还有很大的提升空间
+
+混和主动性分析
+
+- 情感支持指标分析
+
+- KEMI有效的平衡了主动性和非主动性回复
+- KEMI回复的信息更加丰富
+- KEMI容易生成重复性回复
+- KEMI有效地帮助用户解决情绪问题
+
+- 会话进度
+
+- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡
+- KEMI在对话中后期更能主动相应并缓解用户负面情绪
+
+
+案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+
+- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识
+- 通过检索到的知识,进行策略预测和响应生成的多任务学习
+
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势
+## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+
+- 对话主动性分析
+
+- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性
+- 情绪强度预测模型:根据用户话语预测负面情绪强度
+- 用户模拟并注释四种评价指标 :【待看】
+
+- 对话流分析
+
+- ESC在对话中充当主动角色;ED在对话中充当被动角色
+
+- 对话过程
+
+- 研究内容:主动性和情绪强度变化的关系
+- 结论
+
+- 交互时间很重要
+- 情绪缓解后才更有利于解决问题
+
+
+- ES指标
+
+COMET
+
+- 常识性关系
+
+HEAL
+
+- 情绪压力和安慰回应之间的知识图谱
+- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题
+
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。
+# 怎么解决的 / 该方法的优势
+
+
+常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+
+- 人类和系统都可以主动引导交互方向
+- 通过子图检索从心理健康知识图谱中检索外部知识
+
+新的分析方法 > 保留评估 和 混合主动性分析
+方面均有效优于现有方法
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
+- Expression:用户主动
+- Action:系统主动
+- Feedback:用户非主动
+- Reflection:系统非主动
+
+- 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
+- Proactivity:系统主动的对话占系统对话的比例
+- Information:系统首次提出的频繁词占比
+- Repetition:系统重复用户提出的术语的频次占比
+- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的
+
+
+
+相关工作分析
+可以提升的地方
@@ -647,7 +583,8 @@ true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: Knowledge-enhanced Mixed-initiative Dialogue System for Emotional Support Conversations
-
论文速览
-Abstract
--
-
- 混和主动性:按照说话者角色和主动类型分为四类 -
- 提出四个情绪支持指标 -
- 提出一种用于 ESC 的知识增强混合主动框架 (KEMI) -
Introduction
--
-
- ESC系统
-
-
-
- 在适当的时候发起讨论,目的是提出建议,并解决问题 -
- - 相关工作
-
-
-
- CIS(conversational information-seeking)可以主动发起对话,澄清交互并探索更多的信息 -
- 情感推理用来生成共情反应 -
- identifying the dialogue acts of the utterances -
- ESC 系统预测下一个对话策略 -
- - ESC问题的三个挑战
-
-
-
- 系统应该在对话过程中何时采取主动? -
- 系统发起子对话需要什么样的信息? -
- 系统如何促进混合主动交互? -
- - 解决方法
-
-
-
- 策略预测:确定下一回合混合主动策略 -
- 知识选择:收集下一回合的必要知识 -
- 响应生成:在适当的混合主动策略和知识下产生情感支持响应 -
- - 提出的新东西
-
-
-
- 混合主动性特征
-
-
-
- EAFR模式:话语注释为不同类型的说话者角色和主动类型 -
- Expression, Action, Reflection, Feedback -
- - 情感支持指标
-
-
-
- Proactivity, Information, Repetition, Relaxation -
- - KEMI
-
-
-
- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索 -
- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应 -
-
- - 混合主动性特征
-
- 主要贡献
-
-
-
- EAFR 注释模式和四种情感支持指标 -
- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识 -
-
Related Works
--
-
- ESC
-
-
-
- 检测用户情绪 -
- 将情感信号放入Respond中 -
- 情绪感知反应,情感风格转移 -
- 共情对话系统
-
-
-
- 情感推理技巧 -
- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识 -
-
- - 混合主动对话 -
Preliminary Analysis
--
-
- EAFR
-
-
-
- 四种注释方法:按照角色和主动类型区分 -
- 四种评价指标:【待看】 -
- - 混合主动性分析 -
- 混和主动性的挑战
-
-
-
- 系统何时采取主动? -
- 系统发起子对话时,需要什么信息?
-
-
-
- 情感识别:识别用户情感状态 -
- 因果识别:导致情感状态的压力源 -
- 认知识别:解决问题的过程 -
- - 根据历史对话,系统自发判断响应的主动或被动 -
- - 问题定义
-
-
-
- 给定历史对话C和用户情况s,产生相应r
-
-
-
- 策略预测y,细粒度主动性 -
- 知识选择k -
- 使用y和k生成混合主动相应r -
-
- - 给定历史对话C和用户情况s,产生相应r
-
Method
--
-
- 知识获取
-
-
-
- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
-
-
- COMET常识性知识扩展查询:Cp = COMET(p, ut) -
- 构造查询图:û = {ut, {Cp}}
-
-
-
- expectation:ut -
- affective:[xReact] -
- stressor:[xIntent] -
- responses:[xWant] [xNeed] [xEffect] -
- - 子图检索
-
-
-
- 相似度计算:sentence-BERT -
- 针对每个 ût 中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图 -
- 针对每个 E 中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K -
-
-
- - 检索心理健康知识图谱HEAL,弥补常识性知识的不足
-
- 混合主动响应生成
-
-
-
- 使用基于上下文的编码器,编码上下文对话C和知识K -
- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
- - 优化损失函数,最大化负对数似然函数L -
-
Experiment
--
-
- 实验基础
-
-
-
- 数据集:ESConv、MI -
- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n (B-n)、内容保留度ROUGE-L (R-L) -
- - 总体表现
-
-
-
- BlenderBot优于Transformer -
- GLHG、MISI有效地利用了常识性知识 -
- 基于策略的联合学习可以提高性能 -
- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖 -
- - 人工评价
-
-
-
- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜 -
- - 消融实验
-
-
-
- HEAL可以有效提升策略预测准确度 -
- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确 -
- 认知识别是最有效的 -
- 对比Oracle,还有很大的提升空间 -
- - 混和主动性分析
-
-
-
- 情感支持指标分析
-
-
-
- KEMI有效的平衡了主动性和非主动性回复 -
- KEMI回复的信息更加丰富 -
- KEMI容易生成重复性回复 -
- KEMI有效地帮助用户解决情绪问题 -
- - 会话进度
-
-
-
- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡 -
- KEMI在对话中后期更能主动相应并缓解用户负面情绪 -
-
- - 情感支持指标分析
-
- 案例分析 -
Conclusions
--
-
- 首次提出ESC中混和主动性的特点,并阐述其重要性 -
- KEMI框架
-
-
-
- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识 -
- 通过检索到的知识,进行策略预测和响应生成的多任务学习 -
- - 结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势 -
Limitations
--
-
- 评价指标有待改进 -
- 没有考虑不同知识检索方法的不同 -
- 从复杂的KG图中检索知识的方法有待提高 -
- 某些应用的知识图难以获取 -
- 知识库的建立需要具有专业知识的人员 -
Appendix
--
-
- 混和主动性
-
-
-
- 对话主动性分析
-
-
-
- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性 -
- 情绪强度预测模型:根据用户话语预测负面情绪强度 -
- 用户模拟并注释四种评价指标 :【待看】 -
- - 对话流分析
-
-
-
- ESC在对话中充当主动角色;ED在对话中充当被动角色 -
- - 对话过程
-
-
-
- 研究内容:主动性和情绪强度变化的关系 -
- 结论
-
-
-
- 交互时间很重要 -
- 情绪缓解后才更有利于解决问题 -
-
- - ES指标 -
- - 对话主动性分析
-
- COMET
-
-
-
- 常识性关系 -
- - HEAL
-
-
-
- 情绪压力和安慰回应之间的知识图谱 -
- 表现了对话双方的情绪动态,确定缓解情绪的方法 -
-
解决了什么问题
--
-
- 常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。 -
怎么解决的 / 该方法的优势
--
-
- 常识知识生成器 COMET: -
- 常识性知识获取 HEAL: -
有什么创新点
--
-
- 提出ESC知识增强混合主动框架
-
-
-
- 人类和系统都可以主动引导交互方向 -
- 通过子图检索从心理健康知识图谱中检索外部知识 -
- - 新的分析方法 -
--保留评估 和 混合主动性分析 方面均有效优于现有方法
-
-
-
- 按照说话者角色和主动类型将话语注释为不同类型
-
-
-
- Expression:用户主动 -
- Action:系统主动 -
- Feedback:用户非主动 -
- Reflection:系统非主动 -
- - 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
-
-
-
- Proactivity:系统主动的对话占系统对话的比例 -
- Information:系统首次提出的频繁词占比 -
- Repetition:系统重复用户提出的术语的频次占比 -
- Relaxation:情绪强度的改善 -
-
实验结果好在哪里,怎么证明的
-相关工作分析
-可以提升的地方
+Title: Knowledge-enhanced Mixed-initiative Dialogue +System for Emotional Support Conversations
+
论文速览
+Abstract
+-
+
混和主动性:按照说话者角色和主动类型分为四类
+提出四个情绪支持指标
+提出一种用于 ESC 的知识增强混合主动框架 (KEMI) ## +Introduction
+ESC系统
+-
+
- 在适当的时候发起讨论,目的是提出建议,并解决问题 +
+相关工作
+-
+
- CIS(conversational +information-seeking)可以主动发起对话,澄清交互并探索更多的信息 +
- 情感推理用来生成共情反应 +
- identifying the dialogue acts of the utterances +
- ESC 系统预测下一个对话策略 +
+ESC问题的三个挑战
+-
+
- 系统应该在对话过程中何时采取主动? +
- 系统发起子对话需要什么样的信息? +
- 系统如何促进混合主动交互? +
+解决方法
+-
+
- 策略预测:确定下一回合混合主动策略 +
- 知识选择:收集下一回合的必要知识 +
- 响应生成:在适当的混合主动策略和知识下产生情感支持响应 +
+提出的新东西
+-
+
- 混合主动性特征
+
-
+
- EAFR模式:话语注释为不同类型的说话者角色和主动类型 +
- Expression, Action, Reflection, Feedback +
+ - 情感支持指标
+
-
+
- Proactivity, Information, Repetition, Relaxation +
+ - KEMI
+
-
+
- 使用生成的常识知识作为查询图来扩展用户话语,在知识图谱上执行子图检索 +
- 响应生成模块以序列到序列的方式,对策略预测和响应生成进行【多任务学习】,以生成具有外部知识的混合主动响应 +
+
+- 混合主动性特征
+
主要贡献
+-
+
- EAFR 注释模式和四种情感支持指标 +
- 使用用常识知识扩展的查询图,通过子图检索从心理健康知识图谱中检索外部知识 +## Related Works +
+ESC
+-
+
- 检测用户情绪 +
- 将情感信号放入Respond中 +
- 情绪感知反应,情感风格转移 +
- 共情对话系统
+
-
+
- 情感推理技巧 +
- 利用外部知识来提高情绪推理的建模能力:知识图、常识性模型、特定领域知识、常识性知识 +
+
+混合主动对话 ## Preliminary Analysis
+EAFR
+-
+
- 四种注释方法:按照角色和主动类型区分 +
- 四种评价指标:【待看】 +
+混合主动性分析
+混和主动性的挑战
+-
+
- 系统何时采取主动? +
- 系统发起子对话时,需要什么信息?
+
-
+
- 情感识别:识别用户情感状态 +
- 因果识别:导致情感状态的压力源 +
- 认知识别:解决问题的过程 +
+ - 根据历史对话,系统自发判断响应的主动或被动 +
+问题定义
+-
+
- 给定历史对话C和用户情况s,产生相应r
+
-
+
- 策略预测y,细粒度主动性 +
- 知识选择k +
- 使用y和k生成混合主动相应r ## Method +
+
+- 给定历史对话C和用户情况s,产生相应r
+
知识获取
+-
+
- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
-
+
- COMET常识性知识扩展查询:Cp = COMET(p, ut) +
- 构造查询图:û = {ut, {Cp}}
+
-
+
- expectation:ut +
- affective:[xReact] +
- stressor:[xIntent] +
- responses:[xWant] [xNeed] [xEffect] +
+ - 子图检索
+
-
+
- 相似度计算:sentence-BERT +
- 针对每个 ût +中的抽象描述,获取与其最相似的top-K个HEAL中的实体,基于HEAL中的边缘连接,构成候选子图 +
- 针对每个 E +中的类型节点,按照子图中的每个节点相似度得分之和排序子图,选择top-N作为检索到的知识K +
+
+
+- 检索心理健康知识图谱HEAL,弥补常识性知识的不足
+
混合主动响应生成
+-
+
- 使用基于上下文的编码器,编码上下文对话C和知识K +
- X:[CLS]
[know.]<know.>;Y:[strategy]y[response]r
+ - 优化损失函数,最大化负对数似然函数L ## Experiment +
+实验基础
+-
+
- 数据集:ESConv、MI +
- 评估参数:流利度Perplexity (PPL)、内容保留度BLEU-n +(B-n)、内容保留度ROUGE-L (R-L) +
+总体表现
+-
+
- BlenderBot优于Transformer +
- GLHG、MISI有效地利用了常识性知识 +
- 基于策略的联合学习可以提高性能 +
- KEMI明显优于其他方法:HEAL知识相比常识性知识更有效地支持了预测策略,减轻了对预训练大模型的依赖 +
+人工评价
+-
+
- 从流畅度、辨识度、舒适度、建议有效性、总体回应五个方面与BlenderBot-joint、MISC进行对比,MISC完胜 +
+消融实验
+-
+
- HEAL可以有效提升策略预测准确度 +
- 舍弃COMET,可以提高ppl准确度,因为常识性知识不是自然语句;但会降低内容保留度,因为简洁的常识性知识更为精确 +
- 认知识别是最有效的 +
- 对比Oracle,还有很大的提升空间 +
+混和主动性分析
+-
+
- 情感支持指标分析
+
-
+
- KEMI有效的平衡了主动性和非主动性回复 +
- KEMI回复的信息更加丰富 +
- KEMI容易生成重复性回复 +
- KEMI有效地帮助用户解决情绪问题 +
+ - 会话进度
+
-
+
- 相比BlenderBot和MISC,KEMI在对话过程中,主动性和非主动性的分布更加平衡 +
- KEMI在对话中后期更能主动相应并缓解用户负面情绪 +
+
+- 情感支持指标分析
+
案例分析 ## Conclusions
+首次提出ESC中混和主动性的特点,并阐述其重要性
+KEMI框架
+-
+
- 通过查询扩展和子图检索,从大规模心理健康图谱中检索实际病例知识 +
- 通过检索到的知识,进行策略预测和响应生成的多任务学习 +
+结合实际案例和分析指标,结果证明KEMI优于现有方法,并在混合主动交互方面具有优势 +## Limitations
+评价指标有待改进
+没有考虑不同知识检索方法的不同
+从复杂的KG图中检索知识的方法有待提高
+某些应用的知识图难以获取
+知识库的建立需要具有专业知识的人员 ## Appendix
+混和主动性
+-
+
- 对话主动性分析
+
-
+
- 主动性分析模型:在ESConv数据集增加混合主动的类型属性,把历史对话和当前话语作为二元输入,判断主动性。微调RoBERTTalarge,分别训练两个模型,判断用户和系统的主动性 +
- 情绪强度预测模型:根据用户话语预测负面情绪强度 +
- 用户模拟并注释四种评价指标 :【待看】 +
+ - 对话流分析
+
-
+
- ESC在对话中充当主动角色;ED在对话中充当被动角色 +
+ - 对话过程
+
-
+
- 研究内容:主动性和情绪强度变化的关系 +
- 结论
+
-
+
- 交互时间很重要 +
- 情绪缓解后才更有利于解决问题 +
+
+ - ES指标 +
+- 对话主动性分析
+
COMET
+-
+
- 常识性关系 +
+HEAL
+-
+
- 情绪压力和安慰回应之间的知识图谱 +
- 表现了对话双方的情绪动态,确定缓解情绪的方法 # 解决了什么问题 +
+常识性知识是相当抽象的,没有详细的信息,因此它对ESC系统产生有意义和信息丰富的响应的帮助不大。在这项工作中,我们采用生成式常识模型进行查询扩展,从外部知识图中检索实际案例知识。 +# 怎么解决的 / 该方法的优势
+
-
+
常识知识生成器 COMET:
+常识性知识获取 HEAL: # 有什么创新点
+提出ESC知识增强混合主动框架
+-
+
- 人类和系统都可以主动引导交互方向 +
- 通过子图检索从心理健康知识图谱中检索外部知识 +
+新的分析方法 > 保留评估 和 混合主动性分析 +方面均有效优于现有方法
+-
+
- 按照说话者角色和主动类型将话语注释为不同类型
+
-
+
- Expression:用户主动 +
- Action:系统主动 +
- Feedback:用户非主动 +
- Reflection:系统非主动 +
+ - 提出四个情感支持指标来衡量ESC中主动性和非主动性交互的特征
+
-
+
- Proactivity:系统主动的对话占系统对话的比例 +
- Information:系统首次提出的频繁词占比 +
- Repetition:系统重复用户提出的术语的频次占比 +
- Relaxation:情绪强度的改善 # 实验结果好在哪里,怎么证明的 +
+
+- 按照说话者角色和主动类型将话语注释为不同类型
+
相关工作分析
+可以提升的地方
true
+
+
diff --git a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
index 8c68143..5125364 100644
--- a/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
+++ b/2023/MISC_ A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -142,7 +142,7 @@
-
+
@@ -255,157 +255,121 @@
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
-
- 论文速览
- Abstract
-
-- 先前工作的局限性
-
-- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
-- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
-
-
-- 本文提出了MISC
-
-- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
-- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
-
-
-
- Introduction
-
-- 目前的工作不适用于ESC
-
-- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
-- 只有移情反应,而不考虑解决求助者的情感问题
-
-
-- 本文提出的解决方法
-
-- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
-- 混合策略,而不是预测单一策略
-- 设计一套注意力机制
-
-
-- 实验分析
-
-- 回答策略建模的重要性,能够提高模型的共情能力
-
-
-
- Related Work
-
-- 情绪感知响应生成
-- NLP中的常识性知识
-- 策略感知对话模型
-
- Preliminaries
-
-- ESConv数据集
-- 问题设定
-
-- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容
-
-
-
- Model: MISC
-
-- 情感状态增强Encoder
-
-- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x
-
-
-
-Bs=j=1⋃NrCOMET(relj,s)
-
-- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx
-- 将历史对话c输入Encoder得到C
-- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
-- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-- 长对话回复中可以引入多种策略,且模型学习灵活方便
-
-
-
-
-- 多因素感知Decoder
-
-- 将情绪状态和策略表征传入Decoder里的Cross-attention
-
-
-
- Experiments
-
-- ESConv中的每十个话语作为一个样本
-- 评价指标
-
-- 策略预测精度:Acc
-- 传统NLP指标:PPL、BLEU、ROUGE-L
-- 相应多样性:Distinct
-- 人类评估
-
-
-- 基准模型
-
-- MT Transformer、MoEL、MIME、BlenderBot-Joint
-
-
-- 具体实现
-- 实验结果
-
-- 动态细粒度情感标签更能准确给予用户回应
-- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
-- 策略作为单独的任务进行预测比单一预测更有利
-- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识
-
-
-
- Analysis
-
-- 消融实验
-- 案例研究
-- 细粒度情感理解
-
-- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
-
-
-- 混合策略感知移情反应
-
-- 混合策略有利于平滑的情感支持
-- 混合策略比单一策略更有效
-- 混合策略适用于ESC框架
-
-
-
- Conclusions
-
-- 引入COMET来捕捉用户的即时心理状态
-- 设计了一个混合策略感知解码器来产生支持响应
-
- 解决了什么问题 / 怎么解决的
- 该方法的优势
-
-- 长对话中的过度更加顺畅
-
- 有什么创新点
-
-- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
-- 提出了不同的策略模型并在对话中给予提示
-
- 实验结果好在哪里,怎么证明的
-
-- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好
-
- 相关工作分析
- 可以提升的地方
-
-- 以动态的方式学习混合响应策略
-
+ Title: A MIxed Strategy-Aware Model Integrating
+COMET for Emotional Support Conversation
+
+
+论文速览
+Abstract
+
+先前工作的局限性
+
+- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态
+- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦
+
+本文提出了MISC
+
+- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应
+- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处
+## Introduction
+
+目前的工作不适用于ESC
+
+- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化
+- 只有移情反应,而不考虑解决求助者的情感问题
+
+本文提出的解决方法
+
+- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解
+- 混合策略,而不是预测单一策略
+- 设计一套注意力机制
+
+实验分析
+
+- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work
+
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+
+- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ##
+Model: MISC
+
+情感状态增强Encoder
+
+- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x
+
+
+\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+
+- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx
+- 将历史对话c输入Encoder得到C
+- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
+- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size)
+- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
+- 长对话回复中可以引入多种策略,且模型学习灵活方便
+
+
+- 多因素感知Decoder
+
+- 将情绪状态和策略表征传入Decoder里的Cross-attention ##
+Experiments
+
+- ESConv中的每十个话语作为一个样本
+- 评价指标
+
+- 策略预测精度:Acc
+- 传统NLP指标:PPL、BLEU、ROUGE-L
+- 相应多样性:Distinct
+- 人类评估
+
+- 基准模型
+
+- MT Transformer、MoEL、MIME、BlenderBot-Joint
+
+- 具体实现
+- 实验结果
+
+- 动态细粒度情感标签更能准确给予用户回应
+- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助
+- 策略作为单独的任务进行预测比单一预测更有利
+- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ##
+Analysis
+
+- 消融实验
+- 案例研究
+- 细粒度情感理解
+
+- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标
+
+- 混合策略感知移情反应
+
+- 混合策略有利于平滑的情感支持
+- 混合策略比单一策略更有效
+- 混合策略适用于ESC框架 ## Conclusions
+
+- 引入COMET来捕捉用户的即时心理状态
+- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 /
+怎么解决的
+
+该方法的优势
+
+长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 #
+实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 #
+相关工作分析
+
+可以提升的地方
+
+- 以动态的方式学习混合响应策略
+
@@ -493,7 +457,8 @@ true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: A MIxed Strategy-Aware Model Integrating COMET for Emotional Support Conversation
-
论文速览
-Abstract
--
-
- 先前工作的局限性
-
-
-
- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态 -
- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦 -
- - 本文提出了MISC
-
-
-
- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应 -
- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处 -
-
Introduction
--
-
- 目前的工作不适用于ESC
-
-
-
- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化 -
- 只有移情反应,而不考虑解决求助者的情感问题 -
- - 本文提出的解决方法
-
-
-
- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解 -
- 混合策略,而不是预测单一策略 -
- 设计一套注意力机制 -
- - 实验分析
-
-
-
- 回答策略建模的重要性,能够提高模型的共情能力 -
-
Related Work
--
-
- 情绪感知响应生成 -
- NLP中的常识性知识 -
- 策略感知对话模型 -
Preliminaries
--
-
- ESConv数据集 -
- 问题设定
-
-
-
- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 -
-
Model: MISC
--
-
- 情感状态增强Encoder
-
-
-
- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H’s和H’x -
-
Bs=j=1⋃NrCOMET(relj,s)
--
-
- 将H’s和H’x分别与历史对话c做cross-attention,得到Hs和Hx -
- 将历史对话c输入Encoder得到C -
- 混合策略学习模块【从VQ-VAE’s codebook文章中抄来的】
-
-
-
- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size) -
- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
-
-
-
- 长对话回复中可以引入多种策略,且模型学习灵活方便 -
-
- - 多因素感知Decoder
-
-
-
- 将情绪状态和策略表征传入Decoder里的Cross-attention -
-
Experiments
--
-
- ESConv中的每十个话语作为一个样本 -
- 评价指标
-
-
-
- 策略预测精度:Acc -
- 传统NLP指标:PPL、BLEU、ROUGE-L -
- 相应多样性:Distinct -
- 人类评估 -
- - 基准模型
-
-
-
- MT Transformer、MoEL、MIME、BlenderBot-Joint -
- - 具体实现 -
- 实验结果
-
-
-
- 动态细粒度情感标签更能准确给予用户回应 -
- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助 -
- 策略作为单独的任务进行预测比单一预测更有利 -
- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 -
-
Analysis
--
-
- 消融实验 -
- 案例研究 -
- 细粒度情感理解
-
-
-
- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标 -
- - 混合策略感知移情反应
-
-
-
- 混合策略有利于平滑的情感支持 -
- 混合策略比单一策略更有效 -
- 混合策略适用于ESC框架 -
-
Conclusions
--
-
- 引入COMET来捕捉用户的即时心理状态 -
- 设计了一个混合策略感知解码器来产生支持响应 -
解决了什么问题 / 怎么解决的
-该方法的优势
--
-
- 长对话中的过度更加顺畅 -
有什么创新点
--
-
- 提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略 -
- 提出了不同的策略模型并在对话中给予提示 -
实验结果好在哪里,怎么证明的
--
-
- 从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 -
相关工作分析
-可以提升的地方
--
-
- 以动态的方式学习混合响应策略 -
Title: A MIxed Strategy-Aware Model Integrating +COMET for Emotional Support Conversation
+
论文速览
+Abstract
+-
+
先前工作的局限性
+-
+
- 采用对话级别的情感标签,这种标签过于粗粒度,无法捕捉用户的即时精神状态 +
- 大多侧重于在回应中表达同理心,而不是逐渐减轻用户的痛苦 +
+本文提出了MISC
+-
+
- 首先推断用户的细粒度情感状态,然后使用混合策略巧妙地响应 +
- 在基准数据集上的实验结果证明了方法的有效性,并揭示了细粒度情感理解和混合策略建模的好处 +## Introduction +
+目前的工作不适用于ESC
+-
+
- 粗粒度静态的对话级情感标签无法关注到对话过程中用户情感发生的变化 +
- 只有移情反应,而不考虑解决求助者的情感问题 +
+本文提出的解决方法
+-
+
- 有选择地采用COMET(预训练生成式常识推理模型)生成的知识元组进行细粒度情感理解 +
- 混合策略,而不是预测单一策略 +
- 设计一套注意力机制 +
+实验分析
+-
+
- 回答策略建模的重要性,能够提高模型的共情能力 ## Related Work +
+情绪感知响应生成
+NLP中的常识性知识
+策略感知对话模型 ## Preliminaries
+ESConv数据集
+问题设定
+-
+
- 通过对话历史、场景、求助者最后一句话,预测回复策略和回复内容 ## +Model: MISC +
+情感状态增强Encoder
+-
+
- 利用COMET提取场景situation和语句x的常识性知识,将常识性知识输入Encoder得到H's和H'x +
+
\[\boldsymbol{B}^{s}=\bigcup_{j=1}^{N_{r}}\operatorname{COMET}\left(\mathrm{rel}_{j},\boldsymbol{s}\right)\]
+-
+
- 将H's和H'x分别与历史对话c做cross-attention,得到Hs和Hx +
- 将历史对话c输入Encoder得到C +
- 混合策略学习模块【从VQ-VAE's codebook文章中抄来的】
+
-
+
- C输入多层感知机+softmax得到Pg(Pg大小是strategy_size) +
- Pg作为概率分布,hg=Pg*T(T为策略嵌入)
+
-
+
- 长对话回复中可以引入多种策略,且模型学习灵活方便 +
+
+ - 多因素感知Decoder
+
-
+
- 将情绪状态和策略表征传入Decoder里的Cross-attention ## +Experiments +
+ - ESConv中的每十个话语作为一个样本 +
- 评价指标
+
-
+
- 策略预测精度:Acc +
- 传统NLP指标:PPL、BLEU、ROUGE-L +
- 相应多样性:Distinct +
- 人类评估 +
+ - 基准模型
+
-
+
- MT Transformer、MoEL、MIME、BlenderBot-Joint +
+ - 具体实现 +
- 实验结果
+
-
+
- 动态细粒度情感标签更能准确给予用户回应 +
- 细粒度共情,多策略平稳过渡策略,可以更自然地表达共情并提供帮助 +
- 策略作为单独的任务进行预测比单一预测更有利 +
- MISC的知识Know得分最高,成功学习到了COMET中的心理状态知识 ## +Analysis +
+ - 消融实验 +
- 案例研究 +
- 细粒度情感理解
+
-
+
- 用粗粒度的情感标签代替细粒度的心理信息可以显著提高指标 +
+ - 混合策略感知移情反应
+
-
+
- 混合策略有利于平滑的情感支持 +
- 混合策略比单一策略更有效 +
- 混合策略适用于ESC框架 ## Conclusions +
+ - 引入COMET来捕捉用户的即时心理状态 +
- 设计了一个混合策略感知解码器来产生支持响应 # 解决了什么问题 / +怎么解决的 +
该方法的优势
+-
+
长对话中的过度更加顺畅 # 有什么创新点
+提出seq2seq模型MISC,在ESC中添加了常识性知识和混合反应策略
+提出了不同的策略模型并在对话中给予提示 # +实验结果好在哪里,怎么证明的
+从SOTA延续下来的细粒度情感表现较粗粒度静态情感更好 # +相关工作分析
+
可以提升的地方
+-
+
- 以动态的方式学习混合响应策略 +
true
+
+
diff --git a/2023/Recipes for building an open-domain chatbot/index.html b/2023/Recipes for building an open-domain chatbot/index.html
index 9700699..c342f4e 100644
--- a/2023/Recipes for building an open-domain chatbot/index.html
+++ b/2023/Recipes for building an open-domain chatbot/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -140,7 +140,7 @@
-
+
@@ -253,130 +253,103 @@
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Title: Recipes for building an open-domain chatbot
-
-FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
-
- 论文速览
- Abstract
-
-- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
-- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧
-
- Introduction
-
-- 研究的主要内容
-
-- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
-- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
-
-
-- 本文的优势和存在的问题
-
- Model architectures
-
-- 检索
-
-- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
-
-
-- 生成
-
-- 使用标准的Seq2Seq Transformer架构生成响应
-
-
-- 检索和提炼
-
-- 帮助模型访问没有嵌入其模型参数的外部知识
-- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
-- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
-
-
-
- Training Objectives
-
-- 检索排序
-
-- 模型训练使用本文回答作为正例,其他对话回答作为负例
-
-
-- 响应生成模型的似然训练
-
-- 建模整个序列的概率分布
-
-
-- α-混合检索和提炼
-
-- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
-- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
-- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
-
-
-- 响应生成模型的非似然损失
-
-- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
-
-
-
- Decoding
-选择解码方法对给定的历史对话的响应
-
-- 确定性解码方法
-
-- 束搜索
-- 贪心搜索
-
-
-- 采样
-
-- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
-- 平滑分布采样:Temparature+SoftMax+multinomial
-- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
-- sample-and-rank:多次采样,取最高概率的响应
-
-
-- 响应长度
-
-- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
-- 预测长度:根据上下文预测相应长度,这是一个四分类问题
-
-
-- 子序列分块
-
-- n-grams:考虑响应和输入上下文中对于n-grams的重复性
-
-
-
- Training Details
-
-- 预训练排序模型
-- 预训练生成模型
-- 微调
-
-- Fairseq-style混合精度训练
-
-
-
-Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
- 关注的问题 / 本文的优势
-
-- 成对比较和人性方面优于Meena
-
- 解决方法 / 创新点
- 实验结论
- 有待提升的部分
-
-- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
-- 模型倾向于简单的回答
-- 模型倾向于产生重复易混淆的句子
-
+ Title: Recipes for building an open-domain
+chatbot
+
+FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
+
+论文速览
+Abstract
+
+开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ##
+Introduction
+研究的主要内容
+
+- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill
+Talk
+实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。
+- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索
+
+本文的优势和存在的问题 ## Model architectures
+检索
+
+- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】
+
+生成
+
+- 使用标准的Seq2Seq Transformer架构生成响应
+
+检索和提炼
+
+- 帮助模型访问没有嵌入其模型参数的外部知识
+- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应
+- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识
+## Training Objectives
+
+检索排序
+
+- 模型训练使用本文回答作为正例,其他对话回答作为负例
+
+响应生成模型的似然训练
+
+- 建模整个序列的概率分布
+
+α-混合检索和提炼
+
+- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数
+- 知识检索的数据集里,知识条件和响应之间有明确的对应关系
+- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识
+
+响应生成模型的非似然损失
+
+- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差
+## Decoding 选择解码方法对给定的历史对话的响应
+
+确定性解码方法
+
+- 束搜索
+- 贪心搜索
+
+采样
+
+- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样
+- 平滑分布采样:Temparature+SoftMax+multinomial
+- top-k
+sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0
+- sample-and-rank:多次采样,取最高概率的响应
+
+响应长度
+
+- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记
+- 预测长度:根据上下文预测相应长度,这是一个四分类问题
+
+子序列分块
+
+- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training
+Details
+
+预训练排序模型
+预训练生成模型
+微调
+
+- Fairseq-style混合精度训练
+
+
+Training Data Safety Characteristics Evaluation Methods Related Work
+Results & Analysis Released code and models Discussion # 关注的问题
+/ 本文的优势
+
+- 成对比较和人性方面优于Meena # 解决方法 / 创新点
+
+实验结论
+有待提升的部分
+
+- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答
+- 模型倾向于简单的回答
+- 模型倾向于产生重复易混淆的句子
+
@@ -464,7 +437,8 @@ true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: Recipes for building an open-domain chatbot
--- -FaceBook 在本文中提出了 BlenderBot 编解码器模型
-
论文速览
-Abstract
--
-
- 开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致 -
- 本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 -
Introduction
--
-
- 研究的主要内容
-
-
-
- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill Talk 实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。 -
- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索 -
- - 本文的优势和存在的问题 -
Model architectures
--
-
- 检索
-
-
-
- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】 -
- - 生成
-
-
-
- 使用标准的Seq2Seq Transformer架构生成响应 -
- - 检索和提炼
-
-
-
- 帮助模型访问没有嵌入其模型参数的外部知识 -
- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应 -
- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识 -
-
Training Objectives
--
-
- 检索排序
-
-
-
- 模型训练使用本文回答作为正例,其他对话回答作为负例 -
- - 响应生成模型的似然训练
-
-
-
- 建模整个序列的概率分布 -
- - α-混合检索和提炼
-
-
-
- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数 -
- 知识检索的数据集里,知识条件和响应之间有明确的对应关系 -
- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识 -
- - 响应生成模型的非似然损失
-
-
-
- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差 -
-
Decoding
-选择解码方法对给定的历史对话的响应
--
-
- 确定性解码方法
-
-
-
- 束搜索 -
- 贪心搜索 -
- - 采样
-
-
-
- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样 -
- 平滑分布采样:Temparature+SoftMax+multinomial -
- top-k sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0 -
- sample-and-rank:多次采样,取最高概率的响应 -
- - 响应长度
-
-
-
- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记 -
- 预测长度:根据上下文预测相应长度,这是一个四分类问题 -
- - 子序列分块
-
-
-
- n-grams:考虑响应和输入上下文中对于n-grams的重复性 -
-
Training Details
--
-
- 预训练排序模型 -
- 预训练生成模型 -
- 微调
-
-
-
- Fairseq-style混合精度训练 -
-
Training Data
-Safety Characteristics
-Evaluation Methods
-Related Work
-Results & Analysis
-Released code and models
-Discussion
关注的问题 / 本文的优势
--
-
- 成对比较和人性方面优于Meena -
解决方法 / 创新点
-实验结论
-有待提升的部分
--
-
- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答 -
- 模型倾向于简单的回答 -
- 模型倾向于产生重复易混淆的句子 -
Title: Recipes for building an open-domain +chatbot
+++ +FaceBook 在本文中提出了 BlenderBot 编解码器模型
+
论文速览
+Abstract
+-
+
开放域聊天机器人需要良好的谈话技巧:提出有吸引力的要点,倾听别人的意见,适当展示知识、同理性和个性,保持前后一致
+本文证实:基于适当的训练数据和生成策略,大模型可以学习上述技巧 ## +Introduction
+研究的主要内容
+-
+
- 混合技巧:模型专注于个性和吸引力、知识、同理心。采用 Blended Skill +Talk +实现,具体是通过提供训练数据和初始化上下文来实现。这种方法可以减少从大语料库中学习到不良特征。 +
- 生成策略:解码算法非常重要,对话长度强相关于对话质量,本文实验表明采样优于束搜索 +
+本文的优势和存在的问题 ## Model architectures
+检索
+-
+
- 将训练集作为候选响应集,每个可能的候选响应都参与Encoder,并做聚类【poly-encoder】 +
+生成
+-
+
- 使用标准的Seq2Seq Transformer架构生成响应 +
+检索和提炼
+-
+
- 帮助模型访问没有嵌入其模型参数的外部知识 +
- 对话检索:通过检索模型生成响应,并将其附加到Decoder的输入序列中,并用分隔符分开。使用修改后的输入序列生成正常的响应 +
- 知识检索:检索Wiki生成初始候选集,使用上文提到的检索模型,排序候选词并选择条件生成的句子。此外,训练一个分类器,通过上下文判断何时需要检索知识 +## Training Objectives +
+检索排序
+-
+
- 模型训练使用本文回答作为正例,其他对话回答作为负例 +
+响应生成模型的似然训练
+-
+
- 建模整个序列的概率分布 +
+α-混合检索和提炼
+-
+
- 生成模型常常不考虑对话检索语句,为确保其被使用,将检索相应中的α%替换成真实响应,α为超参数 +
- 知识检索的数据集里,知识条件和响应之间有明确的对应关系 +
- 因此训练阶段只使用知识检索的数据,充实模型参数中学到的知识 +
+响应生成模型的非似然损失
+-
+
- 使用高于真实数据数量的n元语法中的token作为候选负样本,修正已知的偏差 +## Decoding 选择解码方法对给定的历史对话的响应 +
+确定性解码方法
+-
+
- 束搜索 +
- 贪心搜索 +
+采样
+-
+
- 多项采样:根据预测结果概率分布,定义候选Token被选中的概率。防止采样到低概率Token,可以将采样限制在词汇表的子集内,并根据子集概率重采样 +
- 平滑分布采样:Temparature+SoftMax+multinomial +
- top-k +sampling:Temparature+Top-k+SoftMax+multinomial,将top-k外的token概率置为0 +
- sample-and-rank:多次采样,取最高概率的响应 +
+响应长度
+-
+
- 约束最小生成长度:在实现最小序列长度之前,强制不生成结束标记 +
- 预测长度:根据上下文预测相应长度,这是一个四分类问题 +
+子序列分块
+-
+
- n-grams:考虑响应和输入上下文中对于n-grams的重复性 ## Training +Details +
+预训练排序模型
+预训练生成模型
+微调
+-
+
- Fairseq-style混合精度训练 +
+
Training Data Safety Characteristics Evaluation Methods Related Work +Results & Analysis Released code and models Discussion # 关注的问题 +/ 本文的优势
+-
+
- 成对比较和人性方面优于Meena # 解决方法 / 创新点 +
实验结论
+有待提升的部分
+-
+
- 如果对话中深入询问某一方面,由于缺乏知识模型没法给出详细的回答 +
- 模型倾向于简单的回答 +
- 模型倾向于产生重复易混淆的句子 +
true
+
+
diff --git a/2023/Towards Emotional Support Dialog Systems/index.html b/2023/Towards Emotional Support Dialog Systems/index.html
index ad633a1..32912de 100644
--- a/2023/Towards Emotional Support Dialog Systems/index.html
+++ b/2023/Towards Emotional Support Dialog Systems/index.html
@@ -140,7 +140,7 @@
-
+
@@ -255,21 +255,19 @@
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: Towards Emotional Support Dialog Systems
- 论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集
-
-
+
Introduction
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升
-
-
+
Related Work
-
-
-
-
+
+
+
Data Collection
- 获取数据集的方法
-
-
+
Data Characteristics
- 数据展示
-
-
+
Experiments
-
+
人类互动评价结果:
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要
-
-
-
-
+
+
Conclusion
- 三个阶段、多种策略、ESConv
-- 道德评估
-
-
+道德评估 # 解决了什么问题
+
- 解决了什么问题
-
-- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
-- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
-- 通过社交而不是专业咨询的方式提供情感支持。
-
- 怎么解决的/该方法的优势
-
-- 基于Hill的帮助技能理论,提出了ESC框架
-
+
+目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 #
+怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+
- 情感支持过程
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action
-
-
-
-
-- 构建ESConv数据集,有丰富的注释(支持策略)
-
+
+
+构建ESConv数据集,有丰富的注释(支持策略)
+
- 每个聊天会都会标记:
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介
-
-
-
-
-- ESC系统
-
+
+
+ESC系统
+
- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】
-- 提出了评估ES实验效果的新方法
+- 提出了评估ES实验效果的新方法 # 有什么创新点
+
-
-
- 有什么创新点
- 实验结果好在哪里,怎么证明的
- 相关工作分析
-
+实验结果好在哪里,怎么证明的
+相关工作分析
+
- 表达情感
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰
-
-
+
- 共情能力
-
+
- 反应出同情心,不能做情绪支持
-
-
+
数据集
-
+
- 数据集中的对话短,不适合ES任务
-
-
+
ESC系统
-
-- 大多研究都人为预先规定好的规则和回复词典
-
-
+
+- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方
+
- 可以提升的地方
@@ -478,7 +453,8 @@ true
+
+
diff --git a/2024/Git/index.html b/2024/Git/index.html
index 86244c9..038b43f 100644
--- a/2024/Git/index.html
+++ b/2024/Git/index.html
@@ -142,7 +142,7 @@
-
+
@@ -258,58 +258,55 @@
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Title: Towards Emotional Support Dialog Systems
-论文速览
+论文速览
- Abstract
- 本文关注于情感支持对话,提供了一个带策略的情绪支持数据集 -
+
- 情感支持应用广泛
- 情绪支持数据集应该包括exploration、understand、suggestion三个过程,还包括有用户的情绪强度变化
- 目前的研究模型中没有具体有效的情绪支持方法;采集数据集时需要训练有素的支持者
- ESC框架:三个阶段,多种策略;众包做数据集;在情绪支持方面有提升 -
- 获取数据集的方法 -
- 数据展示 -
- 微调后ES能力提升
- 带策略微调后能更加适合用户需求
- 正确的策略更重要 -
- 三个阶段、多种策略、ESConv -
- 道德评估 -
解决了什么问题
--
-
- 目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。 -
- 情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。 -
- 通过社交而不是专业咨询的方式提供情感支持。 -
怎么解决的/该方法的优势
--
-
- 基于Hill的帮助技能理论,提出了ESC框架
-
-
+
目前的对话系统没有针对情感支持的任务和语料库,因此ESC方向还没有被探索到,对话场景中缺乏情感支持。
+情感支持(ES)旨在减少个人的情绪困扰,帮助他们理解和应对所面临的挑战。目前的模型大都只能表示共情而不能解决问题。
+通过社交而不是专业咨询的方式提供情感支持。 # +怎么解决的/该方法的优势
+基于Hill的帮助技能理论,提出了ESC框架
+- 情感支持过程
-
-
+
- 理解遇到的困难,exploration
- 表达理解和同情,insight/comforting
- 提出解决问题的方法,action -
-
-- 情感支持过程
-
- 构建ESConv数据集,有丰富的注释(支持策略)
-
-
+
+
-
+
+ 构建ESConv数据集,有丰富的注释(支持策略)
+- 每个聊天会都会标记:
-
-
+
- 问题类别
- 用户情绪类别
- 用户情绪强度
- 遇到困难的简介 -
-
-- 每个聊天会都会标记:
-
- ESC系统
-
-
+
+
ESC系统
+- 选择支持策略,生成策略约束Respond
- 情绪状态建模,跟踪用户情绪变化【待分析】 -
- 提出了评估ES实验效果的新方法 +
- 提出了评估ES实验效果的新方法 # 有什么创新点 +
有什么创新点
-实验结果好在哪里,怎么证明的
-相关工作分析
--
+
- 表达情感
-
-
+
- ECM:情感对话,可以生成情感反应。有情商而不只是智商
- ES:有情绪支持的能力,可以减少用户情绪困扰 -
+ - 共情能力
-
-
+
- 反应出同情心,不能做情绪支持 -
+
实验结果好在哪里,怎么证明的
+相关工作分析
+-
+
- 数据集中的对话短,不适合ES任务 -
-
-
- 大多研究都人为预先规定好的规则和回复词典 -
-
+
- 大多研究都人为预先规定好的规则和回复词典 # 可以提升的地方 +
可以提升的地方
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git
+笔记汇总
- Chapter 1 起步
- 版本控制
-
--
-
集中化版本控制(CVCS)缺点
-
+Chapter 1 起步
+版本控制
+
+- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上
-
-
--
-
分布式版本控制(DVCS)优点
-
+
+- 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互
+
-
-
- Git 简史
-
+Git 简史
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- Git 简介
-
+Git 简介
+
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- Git 配置
+Git 配置
git config --list --show-origin
-
+
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- Chapter 2 基础
+Chapter 2 基础
Git命令只能控制当前文件夹和子文件夹内的修改
- 常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
@@ -319,95 +316,99 @@ 常
- [-s] 简要文件状态信息
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file>
+【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态
+】
+git diff [OPTIONS]
+<file>【已修改文件与已暂存文件的内容差异】
-- [–staged] 显示暂存区和上一次提交的差异
+- [--staged] 显示暂存区和上一次提交的差异
git rm [OPTIONS] <file> 【删除文件】
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
-git commit [OPTIONS] 【提交文件】
-
-- [-m <message>] 提交备注
-- [–amend] 追加提交
-- [-a] 直接将工作区和暂存区的所有修改一起提交
-
+git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 -
+[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息
+- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 -
+[--oneline --graph --all]
+显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since]
+限制时间
+git reset [OPTIONS]
+<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-- [–stat] 显示每次提交的简要信息
-- [-p] 显示每次提交的详细信息
-- [–pretty=format:“xxx”] 自定义信息格式
-- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况
-- [–since] 限制时间
+- [--soft] 回退到某个版本
+- [--mixed]
+默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
+- [--hard]
+撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-- [–soft] 回退到某个版本
-- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变
-- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
-
-git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout
+[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git
+restore 可以代替它】
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支
-- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
+- [-b <local_new_branch_name> <remote_new_branch_name>]
+将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
-git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS]
+【列出当前仓库中已配置的远程仓库】
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL
-- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
-- [remane <old_name> <new_name>] 将已配置的远程仓库重命名
-- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支
+- [add <remote_name> <remote_url>]
+添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中
+- [remane <old_name> <new_name>]
+将已配置的远程仓库重命名
+- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL
+和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库
-- [<remote_name> <new_url>] 修改指定远程仓库的 URL
+- [
] 修改指定远程仓库的 URL
-git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name>
+【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
--
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
--
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
--
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
--
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
--
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+[<remote_name>
+<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>]
+删除远程分支
+[-u <remote_name> --all]
+本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name>
+<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
-git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
+git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中)
-- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验)
+- [-a <version> -m <comment>]
+创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
-git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch>
+【将提交到某一分支上的所有修改都移至另一分支上】
+git revert
+<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout
+类似,但提供了更清晰的语义和错误检查】
- [-c] 创建一个新分支并切换到该分支
-git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
-
-- [.] 还原所有未提交的更改
-- [<filename>] 丢弃工作区修改
-- [–staged <filename>] 将暂存区的修改放回工作区
-- [–source=<commit> <file>] 将文件恢复到特定提交的状态
-
+git show
+【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.]
+还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged
+<filename>] 将暂存区的修改放回工作区 - [--source=<commit>
+<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
- [<branch_name>] 创建本地分支
@@ -416,8 +417,11 @@ 常
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支
-- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支
-- [–merged --no-merged] 合并/未合并到当前分支的其他分支
+- [--set-upstream-to <remotename>/<remote_branch>
+<local_branch>]
+跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git
+pull, git push操作时就不需要指定对应的远程分支
+- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@ 常
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- 忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
- Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
相关命令合并到 Chapter2 中
-
+
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
- 变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史,
+从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
- Chapter 6 GitHub
+Chapter 6 GitHub
@@ -527,7 +533,8 @@
-
+
+
diff --git a/2024/Hexo/index.html b/2024/Hexo/index.html
index 40edd1e..51a7776 100644
--- a/2024/Hexo/index.html
+++ b/2024/Hexo/index.html
@@ -140,7 +140,7 @@
-
+
@@ -257,43 +257,43 @@
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
-有空可以看看这个 Git 笔记汇总
+有空可以看看这个 Git +笔记汇总

Chapter 1 起步
-版本控制
--
-
-
-
集中化版本控制(CVCS)缺点
--
+
- 集中化版本控制(CVCS)缺点
+
- 中央服务器的单点故障就无法协同工作
- 本地只有快照,项目整体和其变更历史只保存在服务器上 -
- -
-
分布式版本控制(DVCS)优点
--
+
+ - 分布式版本控制(DVCS)优点
+
- 代码仓库完整地镜像下来,包括完整的历史记录
- 用户在本地保存了所有改动,每一次的克隆都是对仓库的完整备份
- 可以指定和若干不同的远端代码仓库进行交互 +
Chapter 1 起步
+版本控制
+-
+
- - 集中化版本控制(CVCS)缺点
+
Git 简史
--
+
- 并行开发
- 完全分布式
- 速度快
- 数据量大
- 大多版本控制工具都是基于差异的,存储文件随时间变化的差异,而Git储存项目快照或索引
- Git 安全性优,只做增不做删;完整性好,使用SHA-1 哈希算法
- 文件的四种状态:已提交(committed)、已修改(modified)、已暂存(staged)、未跟踪(untracked)
- 项目的三个阶段:工作目录、暂存区域以及 Git 仓库
- 工作流程:修改文件、暂存文件、将暂存区文件快照永久存在Git目录
- /etc/gitconfig 系统通用配置 git config --system
- ~/.gitconfig 当前用户配置 git config --global
- .git/config 当前项目配置 git config --local
- [-s] 简要文件状态信息
- [–staged] 显示暂存区和上一次提交的差异 +
- [--staged] 显示暂存区和上一次提交的差异
- [-f] 强制移除存在未提交修改的文件
- [ --cached] 文件保留在工作区中,从Git仓库和暂存区中删除
- [-m <message>] 提交备注 -
- [–amend] 追加提交 -
- [-a] 直接将工作区和暂存区的所有修改一起提交 -
- [–stat] 显示每次提交的简要信息 -
- [-p] 显示每次提交的详细信息 -
- [–pretty=format:“xxx”] 自定义信息格式 -
- [–oneline --graph --all] 显示提交历史、各个分支的指向以及项目的分支分叉情况 -
- [–since] 限制时间 +
- [--soft] 回退到某个版本 +
- [--mixed] +默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变 +
- [--hard] +撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交
- [–soft] 回退到某个版本 -
- [–mixed] 默认,用于重置暂存区的文件与上一次的提交保持一致(取消暂存),工作区文件内容保持不变 -
- [–hard] 撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交 -
- [.] 放弃所有工作区的修改
- [-f] 放弃工作区和暂存区的所有修改
- [<branch-name>] 从当前分支切换到指定的分支 -
- [-b <local_new_branch_name> <remote_new_branch_name>] 将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中 +
- [-b <local_new_branch_name> <remote_new_branch_name>] +将远程仓库里指定的分支拉取到本地,并在本地创建一个分支与指定远程仓库分支关联起来,并切换到新建的本地分支中
- [-v] 列出当前仓库中已配置的远程仓库,并显示它们的 URL -
- [add <remote_name> <remote_url>] 添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中 -
- [remane <old_name> <new_name>] 将已配置的远程仓库重命名 -
- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL 和跟踪分支 +
- [add <remote_name> <remote_url>] +添加远程仓库,指定一个远程仓库的名称和 URL,将其添加到当前仓库中 +
- [remane <old_name> <new_name>] +将已配置的远程仓库重命名 +
- [show <remote_name>] 显示指定远程仓库的详细信息,包括 URL +和跟踪分支
- [remove <remote_name>] 从当前仓库中删除指定的远程仓库 -
- [<remote_name> <new_url>] 修改指定远程仓库的 URL +
- [
] 修改指定远程仓库的 URL -
-
[<remote_name> <local_branch_name>:<remote_branch_name>]
-
- -
-
[<remote_name> --delete <branch_name>] 删除远程分支
-
- -
-
[-u <remote_name> --all] 本地的仓库和远程仓库进行关联
-
- -
-
[–set-upstream <remote_branch_name> <local_branch_name>] 将本地分支与远程分支关联
-
- -
-
[–force] 强制提交,会覆盖所有 behind 的提交
-
+ [<remote_name> +<local_branch_name>:<remote_branch_name>]
+[<remote_name> --delete <branch_name>] +删除远程分支
+[-u <remote_name> --all] +本地的仓库和远程仓库进行关联
+[--set-upstream <remote_branch_name> +<local_branch_name>] 将本地分支与远程分支关联
+[--force] 强制提交,会覆盖所有 behind 的提交
- [-l <通配符>] 查询某些对应标签
- [<version>] 轻量标签(提交校验和存储到一个文件中) -
- [-a <version> -m <comment>] 创建附注标签(数据库中的一个完整对象, 可以被校验) +
- [-a <version> -m <comment>] +创建附注标签(数据库中的一个完整对象, 可以被校验)
- [-d] 删除标签
- [-c] 创建一个新分支并切换到该分支
- [.] 还原所有未提交的更改 -
- [<filename>] 丢弃工作区修改 -
- [–staged <filename>] 将暂存区的修改放回工作区 -
- [–source=<commit> <file>] 将文件恢复到特定提交的状态 -
- [<branch_name>] 创建本地分支 @@ -416,8 +417,11 @@
- [-vv] 跟踪信息
- [-r] 查看远程分支
- [-d <branch_name>] 删除分支 -
- [–set-upstream-to <remotename>/<remote_branch> <local_branch>] 跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git pull, git push操作时就不需要指定对应的远程分支 -
- [–merged --no-merged] 合并/未合并到当前分支的其他分支 +
- [--set-upstream-to <remotename>/<remote_branch> +<local_branch>] +跟踪远程分支。在本地新建一个分支后,需要做远程分支关联,目的是在执行git +pull, git push操作时就不需要指定对应的远程分支 +
- [--merged --no-merged] 合并/未合并到当前分支的其他分支
- [-m <old_branch_name> <new_branch_name>] 改名
- [list] 列出所有贮藏
- [apply] 恢复贮藏
- Git 中 HEAD是一个指针,指向当前工作位置
- git mergetool 图形化冲突解决工具
- 有 Git 特性演化出的开发工作流:长期分支、主题分支
Git 简史
+Git 简介
--
+
Git 简介
+Git 配置
+Git 配置
-git config --list --show-origin
-
+
Chapter 2 基础
+Chapter 2 基础
-Git命令只能控制当前文件夹和子文件夹内的修改
常用命令
+常用命令
git init 【初始化仓库】
git clone [OPTIONS] <url>【克隆仓库】
-
@@ -319,95 +316,99 @@
常
-
git add <file> 【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 】
-git diff [OPTIONS] <file>【已修改文件与已暂存文件的内容差异】
+git add <file> +【跟踪新文件、已修改的文件放到暂存区、合并时把有冲突的文件标记为已解决状态 +】
+git diff [OPTIONS] +<file>【已修改文件与已暂存文件的内容差异】
-
-
git rm [OPTIONS] <file> 【删除文件】
git commit [OPTIONS] 【提交文件】
--
-
git commit [OPTIONS] 【提交文件】 - [-m <message>] 提交备注 - +[--amend] 追加提交 - [-a] 直接将工作区和暂存区的所有修改一起提交
git mv <oldfilename> <newfilename> 【移动文件/改名】
-git log [OPTIONS] 【回顾提交历史】
+git log [OPTIONS] 【回顾提交历史】 - [--stat] 显示每次提交的简要信息 +- [-p] 显示每次提交的详细信息 - [--pretty=format:"xxx"] 自定义信息格式 - +[--oneline --graph --all] +显示提交历史、各个分支的指向以及项目的分支分叉情况 - [--since] +限制时间
+git reset [OPTIONS] +<HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
-
-
git reset [OPTIONS] <HEAD>【回退版本,可以指定退回某一次提交的版本,直接删除某些commit的内容】
--
-
git checkout [OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git restore 可以代替它】
+git checkout +[OPTIONS]【在不同的分支之间切换、恢复文件、创建新分支,git switch 和 git +restore 可以代替它】
git remote [OPTIONS] 【列出当前仓库中已配置的远程仓库】
+git remote [OPTIONS] +【列出当前仓库中已配置的远程仓库】
git fetch <remote_name> <local_branch_name> 【获取远程仓库的更新,但不自动合并到你的工作】
+git fetch <remote_name> <local_branch_name> +【获取远程仓库的更新,但不自动合并到你的工作】
git push [OPTIONS]【推送到远程分支】
-
-
git pull <remote_name> <branch>【git fetch
和 git merge
的组合,拉取到本地分支并合并】
git pull <remote_name> <branch>【git fetch
+和 git merge
的组合,拉取到本地分支并合并】
git tag [OPTIONS]【列出已有的标签】
git rebase <cur_branch> <target_branch> 【将提交到某一分支上的所有修改都移至另一分支上】
-git revert <commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
+git rebase <cur_branch> <target_branch> +【将提交到某一分支上的所有修改都移至另一分支上】
+git revert +<commit_id>【生成一次新的commit冲抵原来的commit,不会修改原有的提交历史,而是通过添加新的提交来撤销更改】
git merge <branch> 【合并指定分支到当前分支】
-git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout 类似,但提供了更清晰的语义和错误检查】
+git switch [OPTIONS] <branch-name> 【切换分支,与 git checkout +类似,但提供了更清晰的语义和错误检查】
git show 【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
-git restore [OPTIONS] 【恢复或撤销文件的更改】
--
-
git show +【对于提交,它显示日志消息和文本差异;对于标签,它显示标签消息和引用对象】
+git restore [OPTIONS] 【恢复或撤销文件的更改】 - [.] +还原所有未提交的更改 - [<filename>] 丢弃工作区修改 - [--staged +<filename>] 将暂存区的修改放回工作区 - [--source=<commit> +<file>] 将文件恢复到特定提交的状态
git branch [OPTIONS] 【查看本地分支】
常
git stash [OPTIONS] 【贮藏工作】
@@ -425,21 +429,23 @@常
忽略/不跟踪文件
-.gitignore 正则表达式:官方样例文件
-Chapter 3 分支
+忽略/不跟踪文件
+.gitignore 正则表达式:官方样例文件
+Chapter 3 分支
-相关命令合并到 Chapter2 中
-
+
变基
-如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作。
+变基
+如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。只对尚未推送或分享给别人的本地修改执行变基操作清理历史, +从不对已推送至别处的提交执行变基操作。
工作原理:提取<topicbranch>内的修改并存为临时文件,然后将HEAD指向<basebranch>,最后以此将之前另存为临时文件的修改依序应用
-Chapter 6 GitHub
+Chapter 6 GitHub
- 常用命令
+常用命令
-
+
方法
代码
-
+
快速部署
hexo g -d
-
+
清除缓存
hexo clean
-
+
预览
hexo s
-
+
部署
hexo d
-
+
生成静态页面
hexo generate
- 初始化配置
+初始化配置
初始化项目结构
hexo init
-新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags
-新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories
配置 next 主题设置
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
@@ -416,7 +427,8 @@ DeBug
-
+
+
diff --git a/2024/Stay-Focused/index.html b/2024/Stay-Focused/index.html
index 6bf4341..8443881 100644
--- a/2024/Stay-Focused/index.html
+++ b/2024/Stay-Focused/index.html
@@ -140,7 +140,7 @@
@@ -254,47 +254,48 @@
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
-
常用命令
+常用命令
方法 | 代码 |
---|---|
快速部署 | hexo g -d |
清除缓存 | hexo clean |
预览 | hexo s |
部署 | hexo d |
生成静态页面 | hexo generate |
初始化配置
+初始化配置
初始化项目结构
hexo init |
新增标签页,设置属性(type: “tags”)
+新增标签页,设置属性(type: "tags")
hexo new page tags |
新增分类,设置属性(type: “categories”)
+新增分类,设置属性(type: "categories")
hexo new page categories |
配置 next 主题设置
-
@@ -305,10 +305,13 @@
Git 上传插件
npm install hexo-deployer-git --save
latex 公式
-安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置
+安装 hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置
mathjax:
enable: false
tags: none
katex:
enable: true
copy_tex: false
本地图片
-
+
npm install hexo-asset-img --save // 代替 hexo-asset-image
Markdown 文字高亮
npm install hexo-renderer-markdown-it-plus --save
@@ -321,17 +324,25 @@
sitemap:
path: sitemap.xml
baidusitemap:
path: baidusitemap.xml
改 blockquote 颜色
blockquote {
background: #d0a7020d;
border-left: 4px solid #d0a702;
color: var(--blockquote-color);
margin: 0;
padding: 0 15px;
cite::before {
content: '-';
padding: 0 5px;
}
}
- 备份本地博客
-
+备份本地博客
+
MKLINK [[/D] | [/H] | [/J]] Link Target
/D 创建目录符号链接。默认为文件符号链接。
/H 创建硬链接而非符号链接。
/J 创建目录联接。
Link 指定新的符号链接名称。
Target 指定新链接引用的路径
(相对或绝对)。
-管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
- 2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
+2024.4.23 更新主题 Next
-由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了
+Nunjucks,但是
+目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行
+进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的
+commit 历史。
-按照官网配置
- DeBug
-
+按照官网配置
+DeBug
+
npm install hexo-deployer-git --save |
hexo-renderer-markdown-it-plus
后,Katex 与 mathJax 会重复,需要在 next 中配置hexo-renderer-markdown-it-plus
后,Katex 与 mathJax
+会重复,需要在 next 中配置mathjax: |
npm install hexo-asset-img --save // 代替 hexo-asset-image |
npm install hexo-renderer-markdown-it-plus --save |
sitemap: |
改 blockquote 颜色
blockquote { |
备份本地博客
- +备份本地博客
+MKLINK [[/D] | [/H] | [/J]] Link Target |
管理员 PowerShell cmd /c mklink /D 目标地址 源地址
将博客硬链接到 OneDrive 文件夹下备份
2024.4.23 更新主题 Next
+管理员 PowerShell cmd /c mklink /D 目标地址 源地址
+将博客硬链接到 OneDrive 文件夹下备份
2024.4.23 更新主题 Next
--由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 Nunjucks,但是 目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 commit 历史。
+由于 NexT 以前使用的 swig 模版引擎停止维护,去年迁移到了 +Nunjucks,但是 +目录下的模版文件后缀名没有更改。原因是修改后缀名影响太广,会使用户在执行 +进行更新时产生大量的冲突。这次更换仓库为了解决这些历史遗留问题,没有保留之前的 +commit 历史。
按照官网配置
-DeBug
- +按照官网配置
+DeBug
+
- 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
+ 磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
Thought is already is late, exactly is the earliest time.
- 启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。
-- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
+- 制定一个行动计划。用 10
+分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
- 无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
- 积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
-
+
Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New
+Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the
+Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create
+Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
- 固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
--
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
--
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@ Refer
+
@@ -390,7 +392,8 @@ true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
磨刀不误砍柴工,弄明白如何做事比糊里糊涂的做更重要。当下的目标是通过不断实践试错并总结纠错,从而找到最适合我的高效专注的做事方法。在此,再以高中的座右铭激励自己:当你觉得为时已晚的时候,恰恰是最早的时候。从学生变成社会人、从孩子变成家庭支柱、从做事的变成管人的(总会有那天的啦),我还有很多要改进要学习的地方(如何清楚明确的表达自己的工作内容,如何高效明确的和别人沟通),这些变化不是为了适应社会的表演,而是成年人的责任。(tmd这文字像是初中生写出来的,文化沙漠了属于是,有时间还是得多看看书捏)
-Thought is already is late, exactly is the earliest time.
启动
+启动
布置好工作环境,安排好工作内容,让自己发自内心得希望把事情完成。
- 早起,立即开始工作。早起会立即给自己一个潜意识的信号,让自己在那天努力工作。 -
- 制定一个行动计划。用 10 分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。 +
- 制定一个行动计划。用 10 +分钟来筹划接下来的几个小时要做的事情,让事情可以推动自己前进。
- 提前完成一连串的工作。清晨就处理完当天最紧要的工作,白天的时间就会显得从容,这也会产生积极的启动,这将持续一整天。
无干扰休息
+无干扰休息
休息可以帮助自己以新的方式思考问题,可以清醒头脑,从而重新集中注意力。无干扰的休息意味着休息不会扼杀你的动力,这样你就可以重新振作起来,而不会陷入拖延的弯路。
- 避免参与式的休息。短视频,游戏,微信等会占据头脑的东西都会打断做事的势头。
- 专注于放松。走一小段路、喝一杯水或伸展身体都是不错的选择,可以很容易地从休息中抽身出来回去工作。
休息不是为了玩得开心,这才是真正休息的目的。休息是关于战略性地恢复你的能量和注意力,以重新处理手头的工作。把电视、游戏和娱乐活动留给晚上可以无愧疚地放松的时候。
-积极工作
+积极工作
被动任务比主动任务更难集中注意力。改变这种状况的关键是,或者。
- 使任务处于活动状态。将被动学习任务转换为主动学习任务,如写提纲、记录重点。
- 穿插活动任务。将被动学习与主动任务穿插在一起,以定期提高注意力,如表达自己见解、用自己的话复述一遍。
- +-Step1: choose your concept【写下你要学习的概念】
-Step2: Pretend You’re Teaching the ldea to a New Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
-Step3: If You Get Stuck, Go Back to the Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
-Step4: Simplify and Create Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
+Step2: Pretend You're Teaching the ldea to a New +Student【假象你在教一位不懂这件事情的人这个概念,尝试将这件事情说明白】
+Step3: If You Get Stuck, Go Back to the +Book【如果你在这个过程中遇到了困难,回到课本和视频中进一步学习】
+Step4: Simplify and Create +Analogies【尝试精简自己的解释,并将其与其他概念做类比,从而更好地理解概念】
总结一下,当你可以教会某人一个ta完全不懂的概念的时候,说明你真正掌握了这个概念
固定日程安排
+固定日程安排
努力工作的最好方式就是拥有生活
-
-
-
-
保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
-
- -
-
使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
-
+ 保证休息,应对大量工作任务的办法是保证自己有休息时间。如果你白天不好好工作,却逼迫自己整夜学习的话,你很容易就会筋疲力尽的。无论压力再大任务再多,都要保证休息时间,一颗清醒的大脑决定了工作的质量。
+使用时间分块法或每周/每日目标法,将工作和生活清晰地分离开,好好工作好好玩。
时间分块法
@@ -302,7 +303,8 @@Refer +
true
+
+
diff --git a/404/index.html b/404/index.html
index 6049dfd..e26e231 100644
--- a/404/index.html
+++ b/404/index.html
@@ -19,12 +19,10 @@
-
-
+
-
@@ -204,6 +202,7 @@ 404
+
@@ -266,7 +265,8 @@ 404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
404
-
+
+
diff --git a/Design-Pattern/index.html b/Design-Pattern/index.html
index c8407bf..a0b86c7 100644
--- a/Design-Pattern/index.html
+++ b/Design-Pattern/index.html
@@ -140,7 +140,7 @@
@@ -254,18 +254,23 @@
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- 单例模式
+ 单例模式
双重校验锁
private volatile static Singleton uniqueInstance;
if (uniqueInstance == null) {
//类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
- 模板方法模式
+模板方法模式
抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
-实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
-重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
- 观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
- 适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
+重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
+观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
+适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
单例模式
+单例模式
双重校验锁
private volatile static Singleton uniqueInstance; |
模板方法模式
+模板方法模式
-抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现
实现 AQS 抽象类的锁,需要重写 CLH 锁的 tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
方法。
重写钩子方法,可以自定义 state
的含义:值为多少时代表加锁成功/失败 or 解锁成功/失败,也可以实现共享锁或独占锁。
观察者模式
-具体查看 JUC_Lock 博客的 CompletableFuture
的底层实现
适配器模式
+实现 AQS 抽象类的锁,需要重写 CLH 锁的
+tryAcquire-tryRelease
、tryAcquireShared-tryReleaseShared
、isHeldExclusively
+方法。
重写钩子方法,可以自定义 state
+的含义:值为多少时代表加锁成功/失败 or
+解锁成功/失败,也可以实现共享锁或独占锁。
观察者模式
+具体查看 JUC_Lock 博客的 CompletableFuture
+的底层实现
适配器模式
具体查看 SpringMVC 博客的 HandlerAdapter
的底层实现
开闭原则:新增代替修改
@@ -355,7 +360,8 @@
-
+
+
diff --git a/Docker/index.html b/Docker/index.html
index 932c079..e23bb5c 100644
--- a/Docker/index.html
+++ b/Docker/index.html
@@ -142,7 +142,7 @@
@@ -258,34 +258,43 @@
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
-- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行;
-- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
-- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker;
+- Docker
+Compose:用于定义和运行多容器 Docker
+应用程序的工具,使多个容器可以在隔离环境中一起运行;
+- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明;
+- Docker
+Machine:是一个简化 Docker
+安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的
+docker 主机,比如快速的给 100 台服务器安装上 docker;
- 常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND]
+[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷
-- [–name <NAME>] 命名容器
+- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
-docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER >
+【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
-docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径
-- [–rm] 设置镜像成功后删除中间容器
+- [--rm] 设置镜像成功后删除中间容器
-docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar
+归档文件】
- [-o <xxx.tar>]
@@ -293,9 +302,10 @@ 常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
- 实践
- 如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER>
+【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3'
services:
db:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
MYSQL_DATABASE: mydb
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
ports:
- "3608:3306" # 将宿主机的 3608 端口映射到容器的 3306 端口
java-app:
build:
context: . # 假设 Dockerfile 在当前目录下
dockerfile: Dockerfile
depends_on:
- db
environment:
DB_HOST: db # Java 程序将连接到名为 "db" 的服务(即 MySQL 容器)
DB_PORT: 3306 # 在容器内部,MySQL 仍然监听 3306 端口
DB_USER: myuser
DB_PASSWORD: mypassword
DB_NAME: mydb
ports:
- "8080:8080" # 假设 Java 程序监听 8080 端口
Dockerfile:
@@ -387,7 +397,8 @@ true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定

-
-
- Docker Compose:用于定义和运行多容器 Docker 应用程序的工具,使多个容器可以在隔离环境中一起运行; -
- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明; -
- Docker Machine:是一个简化 Docker 安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker; +
- Docker +Compose:用于定义和运行多容器 Docker +应用程序的工具,使多个容器可以在隔离环境中一起运行; +
- Dockerfile:用来构建镜像的文本文件,包含了一条条构建镜像所需的指令和说明; +
- Docker +Machine:是一个简化 Docker +安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker;可以集中管理所有的 +docker 主机,比如快速的给 100 台服务器安装上 docker;
常用命令
-docker run <IMAGE> [COMMAND] [ARG…]【创建一个新的容器并运行一个命令】
+常用命令
+docker run <IMAGE> [COMMAND] +[ARG...]【创建一个新的容器并运行一个命令】
- [-d] 后台运行容器
- [-p] 指定端口映射
- [-v] 映射主机文件卷 -
- [–name <NAME>] 命名容器 +
- [--name <NAME>] 命名容器
- [-e] 设置环境变量
docker ps [OPTIONS]【列出容器】
- [-a] 显示所有的容器,包括未运行的
docker rm [OPTIONS] <CONTAINER > 【删除一个或多个已经停止的容器】
+docker rm [OPTIONS] <CONTAINER > +【删除一个或多个已经停止的容器】
- [-f] 强制删除正在运行的容器
- [-v] 删除容器挂载的卷
docker build [OPTIONS] <PATH> 【创建镜像】
+docker build [OPTIONS] <PATH> 【创建镜像】
- [-f] 指定要使用的 Dockerfile 路径 -
- [–rm] 设置镜像成功后删除中间容器 +
- [--rm] 设置镜像成功后删除中间容器
docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar 归档文件】
+docker save [OPTIONS] <IMAGE> 【将指定镜像保存成 tar +归档文件】
- [-o <xxx.tar>]
常
- [-i <xxx.tar>] 指定导入的文件
-
docker top [OPTIONS] <CONTAINER> 【查看容器中运行的进程信息,支持 ps 命令参数】
-实践
-如何容器化 Java 应用
+docker top [OPTIONS] <CONTAINER> +【查看容器中运行的进程信息,支持 ps 命令参数】
+实践
+如何容器化 Java 应用
Docker Compose:
version: '3' |
Dockerfile:
@@ -387,7 +397,8 @@true
+
+
diff --git a/How-to-Work/index.html b/How-to-Work/index.html
index fa2a4bd..25eab69 100644
--- a/How-to-Work/index.html
+++ b/How-to-Work/index.html
@@ -140,7 +140,7 @@
@@ -252,7 +252,7 @@
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- 方法论
+ 方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
方法论
+方法论
不卑不亢,谦虚有礼
可以竞争但要避免内斗
及时和领导同步进度
@@ -344,7 +344,8 @@
-
+
+
diff --git a/Interview-Questions/index.html b/Interview-Questions/index.html
index 37e6ce0..261d606 100644
--- a/Interview-Questions/index.html
+++ b/Interview-Questions/index.html
@@ -140,7 +140,7 @@
@@ -254,20 +254,20 @@
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Java-basic
- JVM
-
+ Java-basic
+JVM
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- JUC
-
+JUC
+
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 中间件
-
+中间件
+
- 了解过消息中间件吗?说一下使用场景
@@ -357,7 +357,8 @@ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
--
-
修饰实例方法,锁当前对象实例。
-
-- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
-
-
--
-
修饰静态方法,锁当前类,会作用于所有实例。
-
--
-
修饰同步语句块,程序指定 Object / .class。
-
-- 通过 monitorenter 和 monitorexit 指令实现
-
-
-
-锁粗化和锁消除:
-
-- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
-- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
--
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
--
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
--
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
-- 指向重量级锁的指针 = 指向 monitor 的指针
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
-
-
-实现类可以是独占锁或者共享锁
-
-- 独占锁:tryAcquire-tryRelease
-- 共享锁:tryAcquireShared-tryReleaseShared
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-- 解释一下信号量、倒计时器、可重入锁的 state 的含义
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-- 共享锁:一把锁可以被多个线程同时获得。
-- 独占锁:一把锁只能被一个线程获得。
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+- 修饰实例方法,锁当前对象实例。
+
+- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED
+
+- 修饰静态方法,锁当前类,会作用于所有实例。
+- 修饰同步语句块,程序指定 Object / .class。
+
+- 通过 monitorenter 和 monitorexit 指令实现
+
+
+锁粗化和锁消除:
+
+- 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗
+- 锁消除:Java 虚拟机在 JIT
+编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS
+修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM
+会使用轻量级锁:通过 CAS
+尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset
+环形双向链表;cxq 栈;entrylist 双向链表)
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针
+- 指向重量级锁的指针 = 指向 monitor 的指针
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
+CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+
+实现类可以是独占锁或者共享锁
+
+- 独占锁:tryAcquire-tryRelease
+- 共享锁:tryAcquireShared-tryReleaseShared
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+- 解释一下信号量、倒计时器、可重入锁的 state 的含义
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+- 共享锁:一把锁可以被多个线程同时获得。
+- 独占锁:一把锁只能被一个线程获得。
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。
- 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。
- 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。
- 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
-- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+- 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
,
+则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
- 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。
@@ -302,36 +308,40 @@
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Java-basic
-JVM
--
+
- 了解垃圾回收机制吗?新生代和老年代的垃圾回收是怎么样的
- 简要描述线程与进程的关系,区别及优缺点?
- 线程之间哪些资源是共享的,哪些资源是私有的,为什么?
- 说一下你对于 AQS 原理的理解。
- 如何实现线程安全?
- 了解过消息中间件吗?说一下使用场景
-
-
修饰实例方法,锁当前对象实例。
--
-
- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED -
- -
-
修饰静态方法,锁当前类,会作用于所有实例。
-
- -
-
修饰同步语句块,程序指定 Object / .class。
--
-
- 通过 monitorenter 和 monitorexit 指令实现 -
- - 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗 -
- 锁消除:Java 虚拟机在 JIT 编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间 -
-
-
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS 修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
-
- -
-
轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM 会使用轻量级锁:通过 CAS 尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
-
- -
-
重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作
-LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset 环形双向链表;cxq 栈;entrylist 双向链表)
- - 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针 -
- 指向重量级锁的指针 = 指向 monitor 的指针 -
- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
-
-
-
CANCELLED
表示线程已经被取消【响应中断】
-SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
-CONDITION
表示线程在条件队列中等待某个条件满足【条件队列】
-PROPAGATE
表示共享模式下的资源传播【共享锁】
-
- - 独占锁:tryAcquire-tryRelease -
- 共享锁:tryAcquireShared-tryReleaseShared -
- 解释一下信号量、倒计时器、可重入锁的 state 的含义 -
- 共享锁:一把锁可以被多个线程同时获得。 -
- 独占锁:一把锁只能被一个线程获得。 -
- 修饰实例方法,锁当前对象实例。
+
-
+
- 修饰的方法在编译成字节码的时候,在 flag 上标记 ACC_SYNCHRONIZED +
+ - 修饰静态方法,锁当前类,会作用于所有实例。 +
- 修饰同步语句块,程序指定 Object / .class。
+
-
+
- 通过 monitorenter 和 monitorexit 指令实现 +
+ - 锁粗化:将多次锁请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗 +
- 锁消除:Java 虚拟机在 JIT +编译时,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间 +
偏向锁:只有一个线程持有锁,无竞争情况时,线程可以直接获得锁,没有额外的开销。CAS +修改 Markword 头信息,该操作一般不会撤销,以避免 CAS 开销。
+轻量级锁:多个线程都是在不同的时间段来请求同一把锁时,JVM +会使用轻量级锁:通过 CAS +尝试获取锁,不阻塞线程。如果竞争失败直接会升级成重量级锁,升级过程会自旋尝试获取锁。
+重量级锁:加锁的过程中,采用自适应自旋,避免直接阻塞线程。自旋失败才会阻塞线程并入队,阻塞操作
LockSupport.park
由操作系统来实现,性能消耗高。唤醒线程的策略见下图:(waitset +环形双向链表;cxq 栈;entrylist 双向链表)
+- 指向线程栈中锁记录的指针 = 持有锁线程的 lockRecord 的指针 +
- 指向重量级锁的指针 = 指向 monitor 的指针 +
- waitStatus 状态枚举值(初始值为 0,表示初始化状态)【使用情况】
+
-
+
CANCELLED
表示线程已经被取消【响应中断】
+SIGNAL
表示后继节点的线程需要被唤醒【同步队列】
+CONDITION
+表示线程在条件队列中等待某个条件满足【条件队列】
+PROPAGATE
表示共享模式下的资源传播【共享锁】
+
+ - 独占锁:tryAcquire-tryRelease +
- 共享锁:tryAcquireShared-tryReleaseShared +
- 解释一下信号量、倒计时器、可重入锁的 state 的含义 +
- 共享锁:一把锁可以被多个线程同时获得。 +
- 独占锁:一把锁只能被一个线程获得。 +
- 首先检测线程池运行状态,如果不是
RUNNING
,则直接拒绝,线程池要保证在RUNNING的状态下执行任务。 - 如果
workerCount < corePoolSize
,则创建并启动一个线程来执行新提交的任务。 - 如果
workerCount >= corePoolSize,且线程池内的阻塞队列未满
,则将任务添加到该阻塞队列中。 - 如果
workerCount >= corePoolSize && workerCount < maximumPoolSize,且线程池内的阻塞队列已满
,则创建并启动一个线程来执行新提交的任务。
- - 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, 则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。
+ - 如果
workerCount >= maximumPoolSize,并且线程池内的阻塞队列已满
, +则根据拒绝策略来处理该任务, 默认的处理方式是直接抛异常。 - 通过在入队和出队时进行加锁,保证了队列线程安全
- 支持阻塞的入队和出队方法:当队列满时,会阻塞入队的线程,直到队列不满;当队列为空时,会阻塞出队的线程,直到队列中有元素。 @@ -302,36 +308,40 @@
Java-basic
+JVM
+JUC
--
+
JUC
+中间件
--
+
中间件
+ 中间件
-
+
+
diff --git a/JUC-Lock/index.html b/JUC-Lock/index.html
index 31ecb25..3b321ce 100644
--- a/JUC-Lock/index.html
+++ b/JUC-Lock/index.html
@@ -19,12 +19,12 @@
-
+
-
+
@@ -147,7 +147,8 @@
-
+
@@ -260,228 +261,278 @@
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
-
-锁粗化和锁消除:
-
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-
-实现类可以是独占锁或者共享锁
-
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+
+锁粗化和锁消除:
+
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+
+实现类可以是独占锁或者共享锁
+
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
-此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
-
-简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
- synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
-作用域:
-
-
-锁粗化和锁消除:
-
-
-
-.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
- 锁升级策略
-
-
-
-下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
-
-
-
- ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
-源码结构:
-public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
-ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)
-
- 加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
-然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
- 与 synchronized 对比
-
-
-
-比较
-ReentrantLock
-synchronized
-
-
-
-
-如何实现任务的等待-唤醒?
-Condition 类 await/signal
,可以有选择性的进行线程通知
-Object 的 wait/notify
,被通知的线程是由 JVM 选择的
-
-
-如何释放锁?
-需要手动释放锁
-出代码块后自动释放
-
-
-底层如何实现?
-API 实现
-JVM 内部锁升级策略
-
-
-是否可实现可中断锁、公平锁?
-可以
-不可以
-
-
-占用资源大不大?
-通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
-锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
-
-
-
-可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
- AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
-AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
-
-
-实现类可以是独占锁或者共享锁
-
-
-线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link
-
-在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
- CLH 锁
-
-Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
-CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
-采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-
- LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
-具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
-
-
-
-
-Java 线程中断方法
-方法意义
-
-
-
-
-Thread.currentThread().interrupt()
-将线程的状态置为"中断"
-
-
-Thread.interrupted()
-获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
-
-
-Thread.isInterrupted()
-获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
-
-
-
-阻塞和中断的区别?
-
- Lock 接口
-
-
-
-方法
-描述
-
-
-
-
-lock(): void
-加锁(ReentrantLock 默认不可响应中断)
-
-
-lockInterruptibly(): void
-加锁,阻塞等待锁的过程中,可以相应中断
-
-
-tryLock(): boolean
-非阻塞获取锁
-
-
-tryLock(long, TimeUnit): boolean
-时间段内获取锁
-
-
-unlock(): void
-解锁
-
-
-newCondition(): Condition
-获取条件等待队列
-
-
-
- 公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
- ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
-
-
- StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
- Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
- CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
-CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
- CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+ Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
+此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
+
+简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
+synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
+作用域:
+
+
+锁粗化和锁消除:
+
+
+
+.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead
+Of Time)运行前编译
+
+锁升级策略
+
+
+
+下图是对象头中的 MarkWord:MarkWord
+结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode
+占 32 位)
+
+
+
+ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
+源码结构:
+public class ReentrantLock implements Lock {
// 同步控制器(指向公平锁或非公平锁)
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer{
final boolean nonfairTryAcquire(int acquires) {...}
protected final boolean tryRelease(int releases) {...}
}
// 不公平锁
static final class NonfairSync extends Sync{
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 公平锁
static final class FairSync extends Sync {
final void lock() {...}
protected final boolean tryAcquire(int acquires) {...}
}
// 实现 Lock 接口
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public void unlock() {
sync.release(1);
}
}
+ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)
+
+
+加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
+然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
+与 synchronized 对比
+
+
+
+
+
+
+
+
+比较
+ReentrantLock
+synchronized
+
+
+
+
+如何实现任务的等待-唤醒?
+Condition 类
+await/signal
,可以有选择性的进行线程通知
+Object 的 wait/notify
,被通知的线程是由 JVM 选择的
+
+
+如何释放锁?
+需要手动释放锁
+出代码块后自动释放
+
+
+底层如何实现?
+API 实现
+JVM 内部锁升级策略
+
+
+是否可实现可中断锁、公平锁?
+可以
+不可以
+
+
+占用资源大不大?
+通过自旋CAS
和Unsafe.park/unpark
挂起唤醒线程
+锁升级策略:轻量级锁CAS
不会阻塞挂起;重量级锁才会和ReentrantLock
一样park/unpark
+
+
+
+可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer
+抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
+AQS
+核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过
+CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点==
+维护等待获取资源的线程队列,==state
+成员变量==表示同步状态,每个节点中包括了线程的引用、
+当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
// 表示锁的持有数量
private volatile int state;
// 双向队列(链表实现)
private transient volatile Node head;
private transient volatile Node tail;
// 本地方法 eg:unsafe.compareAndSwapInt
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 封装线程的节点
static final class Node {
// 标识当前节点对应的等待状态(不非负数时,仅作为普通标识,下文有详细介绍)
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
// 共享锁:Semaphore、CountDownLatch
static final Node SHARED = new Node();
// 独占锁:ReentrantLock
static final Node EXCLUSIVE = null;
// 条件队列中,表示下一个节点
// 同步队列中,表示当前节点想要获取的是排他锁还是共享锁
Node nextWaiter;
}
// 条件队列,保存有触发条件的 Node,实现选择性通知
// 作用类似于 Object 内置的监视器方法:wait notify notifyAll
public class ConditionObject implements Condition{
private transient Node firstWaiter;
private transient Node lastWaiter;
}
// 超时中断
static final long spinForTimeoutThreshold = 1000L;
}
+
+
+实现类可以是独占锁或者共享锁
+
+
+线程调度逻辑:
+当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+
+
+在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+
+Craig, Landin, and Hagersten locks
+实现线程阻塞等待以及被唤醒时锁分配的机制
+
+CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
+采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
+
+
+LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
+具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+
+
+
+
+
+
+
+
+Java 线程中断方法
+方法意义
+
+
+
+
+Thread.currentThread().interrupt()
+将线程的状态置为"中断"
+
+
+Thread.interrupted()
+获取当前线程的中断状态,并且会清除线程的状态标记,静态方法
+
+
+Thread.isInterrupted()
+获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别?
+
+
+
+阻塞和中断的区别?
+
+Lock 接口
+
+
+
+
+
+
+
+方法
+描述
+
+
+
+
+lock(): void
+加锁(ReentrantLock 默认不可响应中断)
+
+
+lockInterruptibly(): void
+加锁,阻塞等待锁的过程中,可以相应中断
+
+
+tryLock(): boolean
+非阻塞获取锁
+
+
+tryLock(long, TimeUnit): boolean
+时间段内获取锁
+
+
+unlock(): void
+解锁
+
+
+newCondition(): Condition
+获取条件等待队列
+
+
+
+公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
+ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+
+
+StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
+Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用
+Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
+CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
+CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
@@ -570,7 +621,8 @@ C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁 ReentrantLock
、线程 Callable
FutureTask
、信号量 Semaphore
、共享锁 CountDownLatch
此外 Java 原生的 volatile
和 synchronized
关键字也是并发编程的关键。
简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
synchronized 关键字
-属性:可重入锁、独占锁、非公平锁
-每个对象都有一个 monitor
对象于之关联,synchronized
通过对象监视器 monitor
和操作系统的 Mutex Lock
实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
作用域:
--
-
锁粗化和锁消除:
--
-
--.java -> .class 字节码:Javac
-字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead Of Time)运行前编译
-
锁升级策略
--
-

下图是对象头中的 MarkWord:MarkWord 结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode 占 32 位)
--
-

ReentrantLock
-属性:可重入锁、独占锁、公平锁 or 非公平锁
-特点:可限时等待、可响应中断、可实现选择性通知
-使用场景:阻塞队列 ArrayBlockingQueue
LinkedBlockingDeque
通过 Condition 实现队列满插入和队列空取出的阻塞;作为读写锁 ReentrantReadWriteLock
的父类
源码结构:
-public class ReentrantLock implements Lock { |
ReentrantLock
独占锁运行过程(可重入锁的 state
表示重入的次数,会大于1)

加锁失败时阻塞
-ReentrantLock
在 CAS 加锁失败之后会将 Thread 封装成一个Node
类型的对象加入CLH
队列中
然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个 native 方法实现的工具类,在 hotspot 源码中通过mutex
来实现的)
与 synchronized 对比
-比较 | -ReentrantLock | -synchronized | -
---|---|---|
如何实现任务的等待-唤醒? | -Condition 类 await/signal ,可以有选择性的进行线程通知 |
-Object 的 wait/notify ,被通知的线程是由 JVM 选择的 |
-
如何释放锁? | -需要手动释放锁 | -出代码块后自动释放 | -
底层如何实现? | -API 实现 | -JVM 内部锁升级策略 | -
是否可实现可中断锁、公平锁? | -可以 | -不可以 | -
占用资源大不大? | -通过自旋CAS 和Unsafe.park/unpark 挂起唤醒线程 |
-锁升级策略:轻量级锁CAS 不会阻塞挂起;重量级锁才会和ReentrantLock 一样park/unpark |
-
可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
-不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
-AbstractQueuedSynchronizer 抽象类
-ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS 实现的。AQS 封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
AQS 核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
-CLH 锁:自旋锁的一种改进,利用 FIFO 双端队列 和 Node 节点 维护等待获取资源的线程队列,state 成员变量表示同步状态,每个节点中包括了线程的引用、 当前节点在队列中的状态、前驱节点和后继节点。
-源码结构:
-public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer { |
-
-
实现类可以是独占锁或者共享锁
--
-
线程调度逻辑:
-当线程尝试获取资源失败时,会创建一个Node节点并将当前线程包装进去,然后利用CAS算法将其安全地加入到等待队列的尾部,并阻塞。Link

在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
-CLH 锁
---Craig, Landin, and Hagersten locks 实现线程阻塞等待以及被唤醒时锁分配的机制
-
CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
-
采用模板方法设计模式
-模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
-自定义 Synchronizer
时需要重写几个 AQS 提供的钩子方法(通过钩子方法控制 state
为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
-
LockSupport 类
-操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞 unpark
。Link
具体来说,操作”许可“(多次 unpark 也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
--- -
-- - - -Java 线程中断方法 -方法意义 -- -- Thread.currentThread().interrupt()
将线程的状态置为"中断" -- -- Thread.interrupted()
获取当前线程的中断状态,并且会清除线程的状态标记,静态方法 -- - -- Thread.isInterrupted()
获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别? -阻塞和中断的区别?
-
Lock 接口
-方法 | -描述 | -
---|---|
lock(): void | -加锁(ReentrantLock 默认不可响应中断) | -
lockInterruptibly(): void | -加锁,阻塞等待锁的过程中,可以相应中断 | -
tryLock(): boolean | -非阻塞获取锁 | -
tryLock(long, TimeUnit): boolean | -时间段内获取锁 | -
unlock(): void | -解锁 | -
newCondition(): Condition | -获取条件等待队列 | -
公平锁 & 非公平锁
-AbstractQueuedSynchronizer.hasQueuedPredecessors()
线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
ReentrantReadWriteLock
-继承自 ReentrantLock
-读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
--
-
StampedLock
-不是直接实现 Lock
或 ReadWriteLock
接口,而是基于 CLH 锁 实现的
Semaphore
-信号量,可选择公平 / 非公平锁。
-控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 Redis +Lua 来做限流)
-CountDownLatch
-倒计时器:await()
阻塞当前线程,当 count
为零(即 state)时,唤醒所有被阻塞的线程。
CountDownLatch
是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch
使用完毕后,它不能再次被使用
CyclicBarrier
-循环栅栏:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
+Java.util.concurrent 中有很多 Java 并发相关工具,例如 锁
+ReentrantLock
、线程 Callable
+FutureTask
、信号量 Semaphore
、共享锁
+CountDownLatch
此外 Java 原生的 volatile
和 synchronized
+关键字也是并发编程的关键。
简单的 CAS 实现:AtomicInteger.compareAndSet(1, 2)
synchronized 关键字
+属性:可重入锁、独占锁、非公平锁
+每个对象都有一个 monitor
+对象于之关联,synchronized
通过对象监视器
+monitor
和操作系统的 Mutex Lock
+实现加锁和解锁,被锁住的区域是临界区
:临界区内被锁保护,线程间只能串行访问的代码;
作用域:
+-
+
锁粗化和锁消除:
+-
+
++.java -> .class 字节码:Javac
+字节码 -> 机器码:JIT(Just-in-time)动态(即时)编译;AOT(Ahead +Of Time)运行前编译
+
锁升级策略
+-
+

下图是对象头中的 MarkWord:MarkWord +结构之所以搞得这么复杂,是因为需要节省内存,让同一个内存区域在不同阶段有不同的用处(图有误,hashcode +占 32 位)
+-
+

ReentrantLock
+属性:可重入锁、独占锁、公平锁 or 非公平锁
+特点:可限时等待、可响应中断、可实现选择性通知
+使用场景:阻塞队列 ArrayBlockingQueue
+LinkedBlockingDeque
通过 Condition
+实现队列满插入和队列空取出的阻塞;作为读写锁
+ReentrantReadWriteLock
的父类
源码结构:
+public class ReentrantLock implements Lock { |
ReentrantLock
独占锁运行过程(可重入锁的
+state
表示==重入的次数==,会大于1)

加锁失败时阻塞
+ReentrantLock
在 CAS 加锁失败之后会将 Thread
+封装成一个Node
类型的对象加入CLH
队列中
然后调用LockSupport.park(this)
进行阻塞(LockSupport
是一个
+native 方法实现的工具类,在 hotspot
+源码中通过mutex
来实现的)
与 synchronized 对比
+比较 | +ReentrantLock | +synchronized | +
---|---|---|
如何实现任务的等待-唤醒? | +Condition 类
+await/signal ,可以有选择性的进行线程通知 |
+Object 的 wait/notify ,被通知的线程是由 JVM 选择的 |
+
如何释放锁? | +需要手动释放锁 | +出代码块后自动释放 | +
底层如何实现? | +API 实现 | +JVM 内部锁升级策略 | +
是否可实现可中断锁、公平锁? | +可以 | +不可以 | +
占用资源大不大? | +通过自旋CAS 和Unsafe.park/unpark 挂起唤醒线程 |
+锁升级策略:轻量级锁CAS 不会阻塞挂起;重量级锁才会和ReentrantLock 一样park/unpark |
+
可中断锁:获取锁的过程中可以被中断,不需要一直等到获取锁之后才能进行其他逻辑处理。
+不可中断锁:一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。
+AbstractQueuedSynchronizer +抽象类
+ReentrantLock、倒计时器、信号量的 Sync 和线程池的 worker 都是基于 AQS
+实现的。AQS
+封装了线程的入队与出队、状态更新以及阻塞与唤醒等底层细节,通过重写tryAcquire(int)
、tryRelease(int)
等方法,实现类可以实现具体的资源控制逻辑。
AQS +核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,通过 +CLH 锁实现线程阻塞等待以及被唤醒时锁分配。
+CLH 锁:自旋锁的一种改进,利用 ==FIFO 双端队列== 和 ==Node 节点== +维护等待获取资源的线程队列,==state +成员变量==表示同步状态,每个节点中包括了线程的引用、 +当前节点在队列中的状态、前驱节点和后继节点。
+源码结构:
+public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer { |
-
+
实现类可以是独占锁或者共享锁
+-
+
线程调度逻辑: +当线程尝试获取资源失败时,会创建一个==Node节点==并将当前线程包装进去,然后利用==CAS算法==将其安全地加入到==等待队列的尾部==,并阻塞。Link
+ +
在释放资源时,AQS会根据资源管理策略从队列中选择合适的节点并唤醒对应线程。
+CLH 锁
+++Craig, Landin, and Hagersten locks +实现线程阻塞等待以及被唤醒时锁分配的机制
+
CLH 锁是对自旋锁的一种改良,是一种隐式的链表队列
+
采用模板方法设计模式
+模板方法:抽象出步骤的执行顺序作为抽象方法,具体的实现方法交给子类实现。
+自定义 Synchronizer
时需要重写几个 AQS
+提供的钩子方法(通过钩子方法控制 state
+为何值时代表加锁成功/失败、解锁成功/失败):tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared、isHeldExclusively
-
+
LockSupport 类
+操作 Node 中的 thread,实现线程的阻塞 park
和解除阻塞
+unpark
。Link
具体来说,操作”许可“(多次 unpark
+也只能获取一次许可,不可叠加),底层通过mutex
(互斥量)和condition
(条件变量)实现。【mutex
存在用户态和内核态的切换】
+++
++ + ++ + + + + +Java 线程中断方法 +方法意义 ++ ++ Thread.currentThread().interrupt()
将线程的状态置为"中断" ++ ++ Thread.interrupted()
获取当前线程的中断状态,并且会清除线程的状态标记,静态方法 ++ + ++ Thread.isInterrupted()
获取调用该方法的对象所表示的线程,不会清除线程的状态标记,实例方法阻塞和中断的区别? +阻塞和中断的区别?
+
Lock 接口
+方法 | +描述 | +
---|---|
lock(): void | +加锁(ReentrantLock 默认不可响应中断) | +
lockInterruptibly(): void | +加锁,阻塞等待锁的过程中,可以相应中断 | +
tryLock(): boolean | +非阻塞获取锁 | +
tryLock(long, TimeUnit): boolean | +时间段内获取锁 | +
unlock(): void | +解锁 | +
newCondition(): Condition | +获取条件等待队列 | +
公平锁 & 非公平锁
+AbstractQueuedSynchronizer.hasQueuedPredecessors()
+线程在获取锁前,先判断一下自己在不在队列的首位,只有队首线程能被运行
ReentrantReadWriteLock
+继承自 ReentrantLock
+读锁是共享锁,写锁是独占锁;读读不互斥、读写互斥、写写互斥;写锁可以升级成读锁
+-
+
StampedLock
+不是直接实现 Lock
或
+ReadWriteLock
接口,而是基于 CLH 锁
+实现的
Semaphore
+信号量,可选择公平 / 非公平锁。
+控制同时访问特定资源的线程数量,通常用于那些资源有明确访问数量限制的场景,比如限流(仅限于单机模式,实际项目中推荐使用 +Redis +Lua 来做限流)
+CountDownLatch
+倒计时器:await()
阻塞当前线程,当
+count
为零(即 state)时,唤醒所有被阻塞的线程。
CountDownLatch
+是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当
+CountDownLatch
使用完毕后,它不能再次被使用
CyclicBarrier
+循环栅栏:让==一组线程==到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程都会继续干活。
C
-
+
+
diff --git a/JUC-ThreadPool/index.html b/JUC-ThreadPool/index.html
index 8647a17..81ff2dc 100644
--- a/JUC-ThreadPool/index.html
+++ b/JUC-ThreadPool/index.html
@@ -155,7 +155,9 @@
-
+
@@ -269,29 +271,33 @@
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
- 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
- ThreadPoolExecutor 线程池实现类
+ 池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor
+线程池实现类
执行流程图
线程池生命周期
任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
-
+
- 底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor(
int corePoolSize, //线程池的核心线程数量
int maximumPoolSize, //线程池的最大线程数
long keepAliveTime, //当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue, //任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory, //线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {...}
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
- 阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue
+的主要区别是:
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
public static class testThreadPoolFactory implements ThreadFactory {
private AtomicInteger threadIdx = new AtomicInteger(0);
private String threadNamePrefix;
public testThreadPoolFactory(String Prefix) {
threadNamePrefix = Prefix;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(threadNamePrefix + "-xxljob-" + threadIdx.getAndIncrement());
return thread;
}
}
- 任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定
池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
-ThreadPoolExecutor 线程池实现类
+池化思想,维护一个池子,减少创建/销毁的开销,合理分配系统资源,但会增加调度开销。参考美团技术博客:底层设计思想、业务实现
+ThreadPoolExecutor +线程池实现类
执行流程图

线程池生命周期

任务调度流程
所有任务的调度都是由execute方法完成的,这部分完成的工作是:检查现在线程池的运行状态、运行线程数、运行策略,决定接下来执行的流程,是直接申请线程执行,或是缓冲到队列中执行,亦或是直接拒绝该任务。其执行过程如下:
--
+

底层结构
+底层结构
ThreadPoolExecutor 构造函数
public ThreadPoolExecutor( |
核心线程数:CPU 密集型任务(N+1) I/O 密集型任务(2N) CPU 核心数 N
-阻塞队列 BlockingQueue
+阻塞队列 BlockingQueue
-阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue 的主要区别是:
+阻塞队列中保存即将运行的任务,BlockingQueue 与 Queue +的主要区别是:
+
+
-
+
阻塞队列
描述
-
+
ArrayBlockingQueue
有界队列
-
+
LinkedBlockingQueue
不设置大小的话,默认无界队列
-
+
SynchronousQueue
如果有空闲线程,则使用空闲线程来处理;否则新建一个线程来处理任务
-
+
DelayedWorkQueue
内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序
-
+
PriorityBlockingQueue
优先级阻塞队列
- 创建线程工厂类 ThreadFactory
+创建线程工厂类 ThreadFactory
参数可以设定线程名
@@ -342,31 +352,36 @@
参数可以设定线程名
public static class testThreadPoolFactory implements ThreadFactory { |
任务拒绝策略
+任务拒绝策略
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会拒绝,具体的拒绝策略可以设定