add file
This commit is contained in:
5
.obsidian/community-plugins.json
vendored
5
.obsidian/community-plugins.json
vendored
@@ -1,5 +1,8 @@
|
|||||||
[
|
[
|
||||||
"easy-typing-obsidian",
|
"easy-typing-obsidian",
|
||||||
"cm-editor-syntax-highlight-obsidian",
|
"cm-editor-syntax-highlight-obsidian",
|
||||||
"markdown-prettifier"
|
"markdown-prettifier",
|
||||||
|
"obsidian42-brat",
|
||||||
|
"attachment-flow-plugin",
|
||||||
|
"remotely-save"
|
||||||
]
|
]
|
||||||
1553
.obsidian/plugins/attachment-flow-plugin/main.js
vendored
Normal file
1553
.obsidian/plugins/attachment-flow-plugin/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
.obsidian/plugins/attachment-flow-plugin/manifest.json
vendored
Normal file
1
.obsidian/plugins/attachment-flow-plugin/manifest.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"id":"attachment-flow-plugin","name":"AttachFlow","version":"0.4.3","minAppVersion":"1.0.9","description":"This nifty plugin enables seamless management of attachments and referenced links directly from your documents. Taking advantage of an intuitive right-click menu, you can efficiently handle resources in both LIVE and READ modes.","author":"yaozhuwa","authorUrl":"https://github.com/Yaozhuwa","isDesktopOnly":false,"fundingUrl":"https://www.buymeacoffee.com/yaozhuwa"}
|
||||||
46
.obsidian/plugins/attachment-flow-plugin/styles.css
vendored
Normal file
46
.obsidian/plugins/attachment-flow-plugin/styles.css
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
.attachment-flow-center-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.attachment-flow-log {
|
||||||
|
margin-bottom: 13px;
|
||||||
|
margin-top: 5px;
|
||||||
|
white-space: pre-line; /* enable line break when html parse text containing '\n' */
|
||||||
|
}
|
||||||
|
|
||||||
|
button.mod-warning {
|
||||||
|
background-color: var(--background-modifier-error);
|
||||||
|
color: var(--text-on-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.af-scale-div {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
color: #fff;
|
||||||
|
font-family: var(--default-font);
|
||||||
|
font-size: 20px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-ready-resize {
|
||||||
|
cursor: nwse-resize;
|
||||||
|
outline: 6px solid #dfb0f283;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-ready-click-view {
|
||||||
|
cursor: zoom-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-in-drag-resize {
|
||||||
|
border: 2px solid blue;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 点击查看的大图 */
|
||||||
|
#af-zoomed-image {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
761
.obsidian/plugins/easy-typing-obsidian/main.js
vendored
761
.obsidian/plugins/easy-typing-obsidian/main.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"id": "easy-typing-obsidian",
|
"id": "easy-typing-obsidian",
|
||||||
"name": "Easy Typing",
|
"name": "Easy Typing",
|
||||||
"version": "5.1.10",
|
"version": "5.3.3",
|
||||||
"minAppVersion": "0.15.0",
|
"minAppVersion": "0.15.0",
|
||||||
"description": "Autoformat your note as typing.(Auto captalize, autospace)",
|
"description": "Autoformat your note as typing.(Auto captalize, autospace)",
|
||||||
"author": "yaozhuwa",
|
"author": "yaozhuwa",
|
||||||
|
|||||||
16
.obsidian/plugins/obsidian42-brat/data.json
vendored
Normal file
16
.obsidian/plugins/obsidian42-brat/data.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"pluginList": [
|
||||||
|
"Yaozhuwa/AttachFlow"
|
||||||
|
],
|
||||||
|
"pluginSubListFrozenVersion": [],
|
||||||
|
"themesList": [],
|
||||||
|
"updateAtStartup": true,
|
||||||
|
"updateThemesAtStartup": true,
|
||||||
|
"enableAfterInstall": true,
|
||||||
|
"loggingEnabled": false,
|
||||||
|
"loggingPath": "BRAT-log",
|
||||||
|
"loggingVerboseEnabled": false,
|
||||||
|
"debuggingMode": false,
|
||||||
|
"notificationsEnabled": true,
|
||||||
|
"personalAccessToken": ""
|
||||||
|
}
|
||||||
2419
.obsidian/plugins/obsidian42-brat/main.js
vendored
Normal file
2419
.obsidian/plugins/obsidian42-brat/main.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
15
.obsidian/plugins/obsidian42-brat/manifest.json
vendored
Normal file
15
.obsidian/plugins/obsidian42-brat/manifest.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"id": "obsidian42-brat",
|
||||||
|
"name": "BRAT",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"minAppVersion": "1.4.16",
|
||||||
|
"description": "Easily install a beta version of a plugin for testing.",
|
||||||
|
"author": "TfTHacker",
|
||||||
|
"authorUrl": "https://github.com/TfTHacker/obsidian42-brat",
|
||||||
|
"helpUrl": "https://tfthacker.com/BRAT",
|
||||||
|
"isDesktopOnly": false,
|
||||||
|
"fundingUrl": {
|
||||||
|
"Buy Me a Coffee": "https://bit.ly/o42-kofi",
|
||||||
|
"Visit my site": "https://tfthacker.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
.obsidian/plugins/obsidian42-brat/styles.css
vendored
Normal file
3
.obsidian/plugins/obsidian42-brat/styles.css
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.brat-modal .modal-button-container {
|
||||||
|
margin-top: 5px !important;
|
||||||
|
}
|
||||||
1
.obsidian/plugins/remotely-save/.gitignore
vendored
Normal file
1
.obsidian/plugins/remotely-save/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
data.json
|
||||||
335
.obsidian/plugins/remotely-save/main.js
vendored
Normal file
335
.obsidian/plugins/remotely-save/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
11
.obsidian/plugins/remotely-save/manifest.json
vendored
Normal file
11
.obsidian/plugins/remotely-save/manifest.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"id": "remotely-save",
|
||||||
|
"name": "Remotely Save",
|
||||||
|
"version": "0.4.21",
|
||||||
|
"minAppVersion": "0.13.21",
|
||||||
|
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
|
||||||
|
"author": "fyears",
|
||||||
|
"authorUrl": "https://github.com/fyears",
|
||||||
|
"isDesktopOnly": false,
|
||||||
|
"fundingUrl": "https://github.com/remotely-save/donation"
|
||||||
|
}
|
||||||
87
.obsidian/plugins/remotely-save/styles.css
vendored
Normal file
87
.obsidian/plugins/remotely-save/styles.css
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/* set the styles */
|
||||||
|
|
||||||
|
.password-second-confirm {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-disclaimer {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.encryptionmethod-second-confirm {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-auth-related {
|
||||||
|
border-top: 1px solid var(--background-modifier-border);
|
||||||
|
padding-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.s3-disclaimer {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.s3-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbox-disclaimer {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.dropbox-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbox-auth-button-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropbox-revoke-auth-button-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onedrive-disclaimer {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.onedrive-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onedrive-auth-button-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onedrive-revoke-auth-button-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webdav-disclaimer {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.webdav-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.webdis-disclaimer {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.webdis-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-img {
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ignorepaths-textarea {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logtohttpserver-warning {
|
||||||
|
color: red;
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-need-wrapping-mobile .setting-item-control {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
35
.obsidian/workspace.json
vendored
35
.obsidian/workspace.json
vendored
@@ -19,6 +19,19 @@
|
|||||||
"source": false
|
"source": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1c8e2f0f2e175033",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "markdown",
|
||||||
|
"state": {
|
||||||
|
"file": "并发.md",
|
||||||
|
"mode": "source",
|
||||||
|
"backlinks": true,
|
||||||
|
"source": false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stacked": true
|
"stacked": true
|
||||||
@@ -71,7 +84,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"direction": "horizontal",
|
"direction": "horizontal",
|
||||||
"width": 300
|
"width": 300,
|
||||||
|
"collapsed": true
|
||||||
},
|
},
|
||||||
"right": {
|
"right": {
|
||||||
"id": "572110f2baf458e8",
|
"id": "572110f2baf458e8",
|
||||||
@@ -160,6 +174,8 @@
|
|||||||
},
|
},
|
||||||
"left-ribbon": {
|
"left-ribbon": {
|
||||||
"hiddenItems": {
|
"hiddenItems": {
|
||||||
|
"obsidian42-brat:BRAT": false,
|
||||||
|
"remotely-save:Remotely Save": false,
|
||||||
"switcher:Open quick switcher": false,
|
"switcher:Open quick switcher": false,
|
||||||
"graph:Open graph view": false,
|
"graph:Open graph view": false,
|
||||||
"canvas:Create new canvas": false,
|
"canvas:Create new canvas": false,
|
||||||
@@ -169,9 +185,16 @@
|
|||||||
},
|
},
|
||||||
"active": "157daa1a9b93f46c",
|
"active": "157daa1a9b93f46c",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
"sql语句.md",
|
|
||||||
"代码规范/代码规范.md",
|
|
||||||
"并发.md",
|
"并发.md",
|
||||||
|
"代码规范/代码规范.md",
|
||||||
|
"弱引用.md",
|
||||||
|
"引用类型.md",
|
||||||
|
"内存泄露.md",
|
||||||
|
"Pasted image 20240512214620.png",
|
||||||
|
"补充面试题.md",
|
||||||
|
"并发编程的其他基础知识.md",
|
||||||
|
"慢SQL优化.md",
|
||||||
|
"sql语句.md",
|
||||||
"OOP规约.md",
|
"OOP规约.md",
|
||||||
"可读性.md",
|
"可读性.md",
|
||||||
"事务使用.md",
|
"事务使用.md",
|
||||||
@@ -189,14 +212,8 @@
|
|||||||
"变量规范.md",
|
"变量规范.md",
|
||||||
"常量规范.md",
|
"常量规范.md",
|
||||||
"常量.md",
|
"常量.md",
|
||||||
"logseq-java/pages/变量.md",
|
|
||||||
"Pasted image 20230403123034.png",
|
"Pasted image 20230403123034.png",
|
||||||
"代码规范",
|
"代码规范",
|
||||||
"Java 并发包中并发队列原理剖析.md",
|
|
||||||
"203-Java/203.1-Java面试/205.15-Redis/Redis.md",
|
|
||||||
"203-Java/203.1-Java面试/205.15-Redis/Redis设计与实现.md",
|
|
||||||
"Java 并发包中线程同步器原理剖析.md",
|
|
||||||
"Java 并发包中并发 List 源码剖析.md",
|
|
||||||
"203-Java/Pasted image 20230613181834.png",
|
"203-Java/Pasted image 20230613181834.png",
|
||||||
"203-Java/203.1-Java面试/205.19-网络&操作系统/Pasted image 20230705222905.png",
|
"203-Java/203.1-Java面试/205.19-网络&操作系统/Pasted image 20230705222905.png",
|
||||||
"203-Java/203.1-Java面试/205.19-网络&操作系统/Pasted image 20230708181100.png",
|
"203-Java/203.1-Java面试/205.19-网络&操作系统/Pasted image 20230708181100.png",
|
||||||
|
|||||||
BIN
Pasted image 20240512214620.png
Normal file
BIN
Pasted image 20240512214620.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
161
并发.md
161
并发.md
@@ -8,4 +8,163 @@
|
|||||||
使用阻塞获取等待锁的方式中,必须在 try 代码块之外,并且在加锁方法与 try 代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在 finally 中无法解锁
|
使用阻塞获取等待锁的方式中,必须在 try 代码块之外,并且在加锁方法与 try 代码块之间没有任何可能抛出异常的方法调用,避免加锁成功后,在 finally 中无法解锁
|
||||||
try 中没有加锁 lock. lock ()就解锁 lock. unlock ()会抛出 IllegalMonitorStateException 异常
|
try 中没有加锁 lock. lock ()就解锁 lock. unlock ()会抛出 IllegalMonitorStateException 异常
|
||||||
try 和加锁之间有代码报错,就不会执行 finally 方法报错释放锁
|
try 和加锁之间有代码报错,就不会执行 finally 方法报错释放锁
|
||||||
分布式锁优先使用 redis 锁,而不是数据库锁
|
分布式锁优先使用 redis 锁,而不是数据库锁
|
||||||
|
|
||||||
|
## 线程池中提交一个任务的流程是怎样的?
|
||||||
|
|
||||||
|
使用 executor() 来提交一个工作线程,submit 会放在一个 Future 里面,返回 future
|
||||||
|
提交之后就判断当前worker是都达到核心线程数最大值,如果未达到,就创建线程并执行任务
|
||||||
|
如果达到了核心线程最大数,就将该任务放入队列中
|
||||||
|
如果队列已满,就 addWorker 创建新线程处理任务,如果达到最大线程数,就执行拒绝策略,默认为抛出异常
|
||||||
|
|
||||||
|
## 线程池中有几种状态?分别是如何变化的?
|
||||||
|
|
||||||
|
ctl 变量,AtomicInteger,表示状态
|
||||||
|
RUNNING,会接受新提交的任务
|
||||||
|
SHUTDOWN,shutdown ()不再接受新的任务,已有任务会执行完成
|
||||||
|
STOP,shutdownNow ()不接受新的任务,已有任务也会中止
|
||||||
|
先修改状态,避免新任务进来
|
||||||
|
TYDING,所有线程都终止后,会进入该状态,等待terminated
|
||||||
|
TERMINATED,terminated ()方法执行后进入该状态
|
||||||
|
|
||||||
|
## 如何优雅的停止一个线程
|
||||||
|
|
||||||
|
开启线程,execute (),无需返回值,submit (),需要有返回值,通过 Future. get ()获取
|
||||||
|
Thread t1 = new Thread()
|
||||||
|
t1.stop(), 该方法会直接停止,已经废弃,stop 方法会释放 sync 锁,ReentrantLock 不会释放
|
||||||
|
使用 interrupt 方法,Thread. getCurrent. isInterrupted 可以接受到中断的信号,但是线程自己控制是否停止, 睡眠时被中断会抛出InterruptedException
|
||||||
|
|
||||||
|
## 线程池的核心线程数、最大线程数该如何设置?
|
||||||
|
|
||||||
|
CPU 密集型任务,线程计算任务多,核心线程数+1,避免线程切换时间
|
||||||
|
IO 密集型任务,CPU 利用率不高,线程等待时间长,核心线程数 x2,避免 CPU 闲置
|
||||||
|
线程数=CPU 核心数*(1+等待时间/运行总时间)
|
||||||
|
|
||||||
|
## 如何理解 Java 并发中的可见性?
|
||||||
|
|
||||||
|
多线程修改变量时,一个线程修改了一个变量,然后其他线程可以立刻读取到这个变化的值修改时,如果在缓存就不能被其他线程读取到,使用 volatile 关键字确保读取从内存读取,写入同时写入缓存和内存
|
||||||
|
|
||||||
|
## 如何理解Java并发中的原子性?
|
||||||
|
|
||||||
|
CPU 按照时间片切换,读取值后被切换,其他线程修改了,但是切换回来不会再去读取该值,而是直接去修改该值,需要通过锁机制来保证原子性
|
||||||
|
|
||||||
|
## 如何理解 Java 并发中的有序性?
|
||||||
|
|
||||||
|
![[Pasted image 20240512214620.png]]
|
||||||
|
指令重排序,正常应该先初始化再返回地址
|
||||||
|
编译器优化,修改了执行顺序
|
||||||
|
通过锁和 volatile 关键字避免
|
||||||
|
|
||||||
|
## ForkJoinPool所解决的问题是什么
|
||||||
|
|
||||||
|
RecursiveTask,继承ForkJoinTask
|
||||||
|
当任务可以拆分的时候,就将任务拆分后分不同的线程处理,最后再将所有的计算结果累加
|
||||||
|
可以指定执行的线程数量,默认是机器的线程数量
|
||||||
|
|
||||||
|
## ThreadPoolExecutor的底层实现原理
|
||||||
|
|
||||||
|
addWorker 方法会新开线程
|
||||||
|
如果已经达到了最大核心线程,就会提交到队列中,有空闲的线程就会执行,队列已满会新开线程,直到最大线程数,超过队列就会拒绝新任务
|
||||||
|
|
||||||
|
## ForkJoinPool 拆分任务底层实现分析
|
||||||
|
|
||||||
|
新开一个线程会拆封任务,然后拆分两个线程 join 等待,然后继续拆分任务,直到达到最大线程数据设置
|
||||||
|
执行 compute 方法创建一个队列,把任务放进队列中,然后第一个线程取出该任务,将该大任务拆分,放入队列中,任务 1fork,创建一个自己的队列,将任务 1 取出来任务 2fork,任务 1join,任务 2join,之前的线程等待的时候会取帮助其他线程的任务
|
||||||
|
JDK 19 的虚拟线程也是基于ForkJoinPool
|
||||||
|
## ForkJoinPool的底层核心原理源码解析
|
||||||
|
|
||||||
|
## JDK19中虚拟线程基于ForkJoinPool的相关实现
|
||||||
|
|
||||||
|
## 如何理解 volatile 关键字
|
||||||
|
|
||||||
|
volatile 关键字用于避免指令重排序,同时保证共享变量在内存中的可见性,底层是使用内存屏障来实现的
|
||||||
|
|
||||||
|
## CountDownLatch 和 Semaphore 的区别和底层原理
|
||||||
|
|
||||||
|
countDownLatch 为控制线程等待,让一个线程等待倒计时结束后执行,通过 countDownLatch. awit 方法阻塞,直到为 0 后继续
|
||||||
|
semaphore,让线程通过 acquire 获取许可,获取不到被阻塞,通过 release 方法后返回许可
|
||||||
|
cycilcBarrier,当线程达到屏障时,等待一组线程
|
||||||
|
|
||||||
|
## ReentrantLock中的公平锁和非公平锁的底层实现
|
||||||
|
|
||||||
|
公平锁,去 AQS 排队获取锁
|
||||||
|
非公平锁,竞争锁,没有得到锁就去排队
|
||||||
|
这两种锁都是可重入锁,默认为非公平锁
|
||||||
|
|
||||||
|
## sleep、wait、join、yield
|
||||||
|
|
||||||
|
- 锁池
|
||||||
|
竞争锁的线程都会放入锁池中等待锁
|
||||||
|
|
||||||
|
- 等待池
|
||||||
|
调用 wait 方法会放入等待池中, 不会去竞争锁,只有 notify() 随机或 notifyAll () 会将所有线程放入锁池中
|
||||||
|
|
||||||
|
sleep 是 Thread 的静态方法,wait 是 object 方法
|
||||||
|
sleep 不会释放锁,释放 CPU 执行权,会冻结锁,wait 会释放锁,加入到等待队列中
|
||||||
|
sleep 不依赖 synchornized,wait 依赖 synchornized
|
||||||
|
sleep 不需要被唤醒,wait 需要
|
||||||
|
sleep 用于线程休眠或轮询暂停操作,wait 用于线程间通信
|
||||||
|
sleep 会让出 CPU 执行时间并强制上下文切换,wait 不一定,wait 后可能还是会有机会竞争到锁重新执行
|
||||||
|
|
||||||
|
yield 执行后线程进入就绪状态,释放了 cpu 执行权,但是保留了执行资格,还是可能下次线程调度继续执行
|
||||||
|
|
||||||
|
join 执行后线程阻塞,直到其他线程结束或中断线程
|
||||||
|
|
||||||
|
## Sychronized的偏向锁、轻量级锁、重量级锁
|
||||||
|
|
||||||
|
首先是无锁,然后当有线程获取锁的时候,会在对象头中记录下线程的 id,后面该线程来获取该锁的时候会直接获取锁,当有线程竞争之后,该锁升级成为轻量级锁,轻量级锁为自旋锁,自旋锁通过 CAS 获取预期的一个标记不会阻塞线程,当自旋过多时升级为重量级锁,重量级锁会阻塞线程
|
||||||
|
全局安全点执行清理任务的时候会尝试触发降级锁
|
||||||
|
|
||||||
|
## ThreadLocal 的底层原理
|
||||||
|
|
||||||
|
ThreadLocal 可以将数据缓存在一个线程内,每一个 Thread 对象都有一个 ThreadLocalMap,这个 Map 里面 key 为对应的 ThreadLocal,值为设置的缓存值,读取的时候以该 ThreadLocal 为引用,在自己的 map 里找对应的 key,
|
||||||
|
|
||||||
|
## ThreadLocal的原理的使用场景
|
||||||
|
|
||||||
|
数据库连接池,session 会话管理
|
||||||
|
连接管理,一个线程持有一个连接,该连接对象不在线程间共享
|
||||||
|
对象跨层传输时,避免多次传递
|
||||||
|
线程间数据隔离
|
||||||
|
事务操作时,存储线程事务信息
|
||||||
|
|
||||||
|
## ThreadLocal[[内存泄露]]问题,如何避免
|
||||||
|
|
||||||
|
线程和 ThreadLocalMap 是强引用,Map 和 ThreadLocal 的 Entity 也是强引用,Entry 的 key 是 ThreadLocal 对象,是一个[[弱引用]],没有指向 key 的强引用该 ThreadLocal 就会被垃圾回收器回收,使用完成之后线程没有回收,但是 Entry 中的 value 是强引用不会被回收,只有线程结束才会回收,value 对象过多的时候就会导致内存泄漏,但是只要调用 get 或 set 方法就可以清理掉需要使用之后手动调用 remove 方法来清除该值
|
||||||
|
|
||||||
|
## 阿里一面:如何查看线程死锁
|
||||||
|
|
||||||
|
## 阿里一面:线程之间如何进行通讯的
|
||||||
|
|
||||||
|
## 并发、并行、串行
|
||||||
|
|
||||||
|
## 并发篇1
|
||||||
|
|
||||||
|
## 并发篇2-1
|
||||||
|
|
||||||
|
## 并发篇2-2
|
||||||
|
|
||||||
|
## 并发篇3
|
||||||
|
|
||||||
|
## 并发4
|
||||||
|
|
||||||
|
## 并发5
|
||||||
|
|
||||||
|
## 并发三大特性
|
||||||
|
|
||||||
|
## 对线程安全的理解
|
||||||
|
|
||||||
|
## 京东一面:Java死锁如何避免
|
||||||
|
|
||||||
|
## 京东一面:如果你提交任务时,线程池队列已满,这时会发生什么
|
||||||
|
|
||||||
|
## 蚂蚁一面:sychronized的自旋锁、偏向锁、轻量级锁、重量级锁,分别介绍和联系
|
||||||
|
|
||||||
|
## 说说你对守护线程的理解
|
||||||
|
|
||||||
|
## 为什么使用线程池,参数解释
|
||||||
|
|
||||||
|
## 线程的生命周期及状态
|
||||||
|
|
||||||
|
## 线程池线程复用的原理
|
||||||
|
|
||||||
|
## 线程池的底层工作原理
|
||||||
160
慢SQL优化.md
Normal file
160
慢SQL优化.md
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
## 优化方式
|
||||||
|
数据量
|
||||||
|
- SQL 执行后返回给客户端的数据量的大小
|
||||||
|
- 数据量越大需要扫描的 I/O 次数越多,数据库服务器的 IO 瓶颈
|
||||||
|
取数据的方式
|
||||||
|
- 数据在缓存还是磁盘
|
||||||
|
- 能否通过全局索引快速寻址
|
||||||
|
- 是否结合谓词条件命中全局索引加速扫描
|
||||||
|
数据加工的方式
|
||||||
|
- 排序、子查询、聚合、关联等需要将数据取到临时表中,再对数据加工
|
||||||
|
- 对于数据量多的计算,会消耗大量 CPU 资源
|
||||||
|
- 是否选择了合适的 join 方式
|
||||||
|
## 优化思路
|
||||||
|
减少数据扫描(磁盘访问)
|
||||||
|
- 尽量在查询中加入一些可以提前过滤数据的位于条件,减少数据扫描量,对查询更加友好
|
||||||
|
- 扫描大表数据时是否可以命中索引,减少回表,避免全表扫描
|
||||||
|
返回更少数据(减少网络传输或磁盘访问)
|
||||||
|
减少交互次数(减少网络传输)
|
||||||
|
- 将数据存放在更快的地方
|
||||||
|
- 某条查询涉及大表,无法进一步优化,如果返回数据量不大但访问频率很高,可以将返回的数据放在应用端缓存或 redis 缓存中,提高存取速度
|
||||||
|
减少服务器开销(CPU 和内存)
|
||||||
|
避免大事务
|
||||||
|
利用更多资源
|
||||||
|
## 优化案例
|
||||||
|
- 数据分页优化
|
||||||
|
```sql
|
||||||
|
select * from table_name where type = ? limit ?,?;
|
||||||
|
```
|
||||||
|
偏移 id
|
||||||
|
```sql
|
||||||
|
lastId = 0 or min(id)
|
||||||
|
do {
|
||||||
|
select * from table_name where type = ? and id > {#lastId} limit ?;
|
||||||
|
lastId = max(id)
|
||||||
|
} while (isNotEmpty)
|
||||||
|
```
|
||||||
|
分段查询
|
||||||
|
优点:可并行查询,分段互不依赖
|
||||||
|
缺点:依赖连续性,数据过于分散代价较高
|
||||||
|
```sql
|
||||||
|
minId = min(id) maxId = max(id)
|
||||||
|
for(int i = minId; i <= maxId; i+=pageSize){
|
||||||
|
select * from table_name where type = ? and id between i and i+ pageSize;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- 优化 groupBy
|
||||||
|
将不需要的数据在 groupBy 之前过滤掉
|
||||||
|
```sql
|
||||||
|
select job, avg(sal) from table_name group by job having job = 'manager'
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select job, avg(sal) from table_name where job = 'manager' group by job
|
||||||
|
```
|
||||||
|
- 范围查询
|
||||||
|
联合索引中如果某个列存在范围查询(大于小于),其右边的列是否还有意义
|
||||||
|
设计时需要结合业务需求
|
||||||
|
- 优化 order by
|
||||||
|
索引
|
||||||
|
```sql
|
||||||
|
KEY `idx_account_trade_date_time` (`account_number`,`trade_date_time`)
|
||||||
|
KEY `idx_trade_date_time` (`trade_date_time`)
|
||||||
|
KEY `idx_create_time` (`create_time`)
|
||||||
|
```
|
||||||
|
慢 SQL
|
||||||
|
```sql
|
||||||
|
select id,,,creator,modifier,create_time,update_time from satatement where (account_number = 'XXX' and create_time > '2024-04-24 00:00:00' and create_time < '2024-04-25 00:00:00' and dc_flag = 'C') order by trade_date_time desc, id desc limit 0,1000;
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
select id,,,creator,modifier,create_time,update_time from satatement where (account_number = 'XXX' and create_time > '2024-04-24 00:00:00' and create_time < '2024-04-25 00:00:00' and dc_flag = 'C') order by create_time desc, id desc limit 0,1000;
|
||||||
|
```
|
||||||
|
MySQL 使不使用索引与所查列无关,只与索引本身,where 条件,order by group by 字段有关,索引的作用为查找和排序
|
||||||
|
- 业务拆分
|
||||||
|
```sql
|
||||||
|
select * from order where status = 'S' and update_time < now-5min limit 500
|
||||||
|
```
|
||||||
|
业务数据增长,status 无法走索引,结合业务特性,对数据获取按日期拆分
|
||||||
|
```sql
|
||||||
|
date = now; minDate = now - 10 day
|
||||||
|
while(date > minDate) {
|
||||||
|
select * from order where order_date = #{date} and status = 'S' and update_time < now-5min limit 500
|
||||||
|
date = date + 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## 数据库结构优化
|
||||||
|
- 范式优化:表的设计合理化(3 NF),消除冗余(节省空间)
|
||||||
|
- 反范式优化:适当添加冗余(减少 join)
|
||||||
|
- 拆分表:分区将数据在物理上分隔开,不同分区数据表存储于不同磁盘中,查询时只需到表分区中扫描,无需全表扫描,同时分散了磁盘 IO
|
||||||
|
## SQL 语句优化
|
||||||
|
1. 避免子查询
|
||||||
|
2. 用 in 替换 or
|
||||||
|
3. 读取适当的记录 limit M,N,不要读取多余的记录
|
||||||
|
4. 禁止不必要的 order by 排序
|
||||||
|
5. 总和查询禁止排重用 union all
|
||||||
|
6. 避免随机取数据
|
||||||
|
7. 将多次插入换成批量插入
|
||||||
|
8. 只返回必要的列,select 具体字段
|
||||||
|
9. 区分 in 和 exist
|
||||||
|
10. 优化 group by
|
||||||
|
11. 尽量使用数字型字段
|
||||||
|
12. 优化 join 语句
|
||||||
|
## 大表优化
|
||||||
|
- 分库分表
|
||||||
|
- 读写分离
|
||||||
|
- 数据定期归档
|
||||||
|
## 索引的优缺点
|
||||||
|
优点
|
||||||
|
- 提高查询语句执行效率,减少 IO 操作次数
|
||||||
|
- 创建唯一性索引,保证数据库中每一行数据的唯一性
|
||||||
|
- 加索引的列会进行排序,使用分组和排序子句可以减少时间
|
||||||
|
缺点
|
||||||
|
- 索引需要占用一定空间
|
||||||
|
- 创建索引和维护索引需要时间
|
||||||
|
- 对表中数据进行修改时,索引也要动态维护,降低了更新效率
|
||||||
|
## 索引结构
|
||||||
|
## 数据行格式
|
||||||
|
MySQL 有 4 种存储格式:
|
||||||
|
1. Compact
|
||||||
|
2. Redundant(5.0 版本前,已废弃)
|
||||||
|
3. Dynamic(MySQL 5.7 默认格式)
|
||||||
|
4. Compressed
|
||||||
|
Dynamic 下,对于处理行溢出,仅存放溢出页内存地址
|
||||||
|
## 索引设计原则
|
||||||
|
哪些情况适合建索引
|
||||||
|
- 数据有唯一性限制
|
||||||
|
- 频繁 where 条件
|
||||||
|
- 进场 group by 和 order by 字段,都有时建议联合索引
|
||||||
|
- 经常 distinct 字段
|
||||||
|
- 多表连接时的字段
|
||||||
|
- 数量最好不要超过 3 张
|
||||||
|
- 多表查询时 where 条件建索引
|
||||||
|
- 对连接字段建索引,且数据类型保持一致
|
||||||
|
- 确定数据范围情况下使用数据类型较小的字段,索引也会占空间
|
||||||
|
- 字符串建索引使用前缀
|
||||||
|
- 节省空间
|
||||||
|
- 可定位到相同前缀,然后通过主键查询完整字符串
|
||||||
|
- 区分度高的字段(散列性高)的字段
|
||||||
|
- 多个字段需要建索引,联合索引优于单值索引
|
||||||
|
不需要索引
|
||||||
|
- where 条件中用不到
|
||||||
|
- 数据量小,小于 1000 条
|
||||||
|
- 大量重复数据的列
|
||||||
|
- 避免在经常更新的表或字段
|
||||||
|
- 不建议主键使用无序的值
|
||||||
|
- 不定义冗余或重复索引
|
||||||
|
- 已有联合索引不要单独再建单索引
|
||||||
|
## 索引优化之 MRR
|
||||||
|
## 索引下推
|
||||||
|
idx (name, age)
|
||||||
|
```sql
|
||||||
|
select * from tuser where name like '张%' and age=10;
|
||||||
|
```
|
||||||
|
直接在联合索引里面过滤过滤两次完后在回表
|
||||||
|
条件
|
||||||
|
- 只能用于 range、ref、eq_ref、ref_or_null 访问方法
|
||||||
|
- 只使用 InnoDB 和 MyISAM
|
||||||
|
- 对存储引擎来说,只适用于二级索引(辅助索引)
|
||||||
|
- 引用了子查询的条件不能下推
|
||||||
|
- 引用了存储函数的条件不能下推,存储引擎无法调用存储函数
|
||||||
Reference in New Issue
Block a user