|
| 1 | +<?xml version="1.0" encoding="utf-8"?> |
| 2 | +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
| 3 | +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| 4 | +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> |
| 5 | +<head> |
| 6 | +<title>锁的设计模型</title> |
| 7 | +<!-- 2017-10-12 周四 10:36 --> |
| 8 | +<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> |
| 9 | +<meta name="generator" content="Org-mode" /> |
| 10 | +<meta name="author" content="王月阳" /> |
| 11 | +<meta name="description" content="单机或者分布式环境中,锁的模型与设计" |
| 12 | + /> |
| 13 | +<meta name="keywords" content="Java concurrenty 多线程 AQS Java锁 资源争用" /> |
| 14 | +<style type="text/css"> |
| 15 | + <!--/*--><![CDATA[/*><!--*/ |
| 16 | + .title { text-align: center; } |
| 17 | + .todo { font-family: monospace; color: red; } |
| 18 | + .done { color: green; } |
| 19 | + .tag { background-color: #eee; font-family: monospace; |
| 20 | + padding: 2px; font-size: 80%; font-weight: normal; } |
| 21 | + .timestamp { color: #bebebe; } |
| 22 | + .timestamp-kwd { color: #5f9ea0; } |
| 23 | + .right { margin-left: auto; margin-right: 0px; text-align: right; } |
| 24 | + .left { margin-left: 0px; margin-right: auto; text-align: left; } |
| 25 | + .center { margin-left: auto; margin-right: auto; text-align: center; } |
| 26 | + .underline { text-decoration: underline; } |
| 27 | + #postamble p, #preamble p { font-size: 90%; margin: .2em; } |
| 28 | + p.verse { margin-left: 3%; } |
| 29 | + pre { |
| 30 | + border: 1px solid #ccc; |
| 31 | + box-shadow: 3px 3px 3px #eee; |
| 32 | + padding: 8pt; |
| 33 | + font-family: monospace; |
| 34 | + overflow: auto; |
| 35 | + margin: 1.2em; |
| 36 | + } |
| 37 | + pre.src { |
| 38 | + position: relative; |
| 39 | + overflow: visible; |
| 40 | + padding-top: 1.2em; |
| 41 | + } |
| 42 | + pre.src:before { |
| 43 | + display: none; |
| 44 | + position: absolute; |
| 45 | + background-color: white; |
| 46 | + top: -10px; |
| 47 | + right: 10px; |
| 48 | + padding: 3px; |
| 49 | + border: 1px solid black; |
| 50 | + } |
| 51 | + pre.src:hover:before { display: inline;} |
| 52 | + pre.src-sh:before { content: 'sh'; } |
| 53 | + pre.src-bash:before { content: 'sh'; } |
| 54 | + pre.src-emacs-lisp:before { content: 'Emacs Lisp'; } |
| 55 | + pre.src-R:before { content: 'R'; } |
| 56 | + pre.src-perl:before { content: 'Perl'; } |
| 57 | + pre.src-java:before { content: 'Java'; } |
| 58 | + pre.src-sql:before { content: 'SQL'; } |
| 59 | + |
| 60 | + table { border-collapse:collapse; } |
| 61 | + caption.t-above { caption-side: top; } |
| 62 | + caption.t-bottom { caption-side: bottom; } |
| 63 | + td, th { vertical-align:top; } |
| 64 | + th.right { text-align: center; } |
| 65 | + th.left { text-align: center; } |
| 66 | + th.center { text-align: center; } |
| 67 | + td.right { text-align: right; } |
| 68 | + td.left { text-align: left; } |
| 69 | + td.center { text-align: center; } |
| 70 | + dt { font-weight: bold; } |
| 71 | + .footpara:nth-child(2) { display: inline; } |
| 72 | + .footpara { display: block; } |
| 73 | + .footdef { margin-bottom: 1em; } |
| 74 | + .figure { padding: 1em; } |
| 75 | + .figure p { text-align: center; } |
| 76 | + .inlinetask { |
| 77 | + padding: 10px; |
| 78 | + border: 2px solid gray; |
| 79 | + margin: 10px; |
| 80 | + background: #ffffcc; |
| 81 | + } |
| 82 | + #org-div-home-and-up |
| 83 | + { text-align: right; font-size: 70%; white-space: nowrap; } |
| 84 | + textarea { overflow-x: auto; } |
| 85 | + .linenr { font-size: smaller } |
| 86 | + .code-highlighted { background-color: #ffff00; } |
| 87 | + .org-info-js_info-navigation { border-style: none; } |
| 88 | + #org-info-js_console-label |
| 89 | + { font-size: 10px; font-weight: bold; white-space: nowrap; } |
| 90 | + .org-info-js_search-highlight |
| 91 | + { background-color: #ffff00; color: #000000; font-weight: bold; } |
| 92 | + /*]]>*/--> |
| 93 | +</style> |
| 94 | +<link rel="stylesheet" type="text/css" href="./css/style.css" /> |
| 95 | +<script type="text/javascript"> |
| 96 | +/* |
| 97 | +@licstart The following is the entire license notice for the |
| 98 | +JavaScript code in this tag. |
| 99 | +
|
| 100 | +Copyright (C) 2012-2013 Free Software Foundation, Inc. |
| 101 | +
|
| 102 | +The JavaScript code in this tag is free software: you can |
| 103 | +redistribute it and/or modify it under the terms of the GNU |
| 104 | +General Public License (GNU GPL) as published by the Free Software |
| 105 | +Foundation, either version 3 of the License, or (at your option) |
| 106 | +any later version. The code is distributed WITHOUT ANY WARRANTY; |
| 107 | +without even the implied warranty of MERCHANTABILITY or FITNESS |
| 108 | +FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. |
| 109 | +
|
| 110 | +As additional permission under GNU GPL version 3 section 7, you |
| 111 | +may distribute non-source (e.g., minimized or compacted) forms of |
| 112 | +that code without the copy of the GNU GPL normally required by |
| 113 | +section 4, provided you include this license notice and a URL |
| 114 | +through which recipients can access the Corresponding Source. |
| 115 | +
|
| 116 | +
|
| 117 | +@licend The above is the entire license notice |
| 118 | +for the JavaScript code in this tag. |
| 119 | +*/ |
| 120 | +<!--/*--><![CDATA[/*><!--*/ |
| 121 | + function CodeHighlightOn(elem, id) |
| 122 | + { |
| 123 | + var target = document.getElementById(id); |
| 124 | + if(null != target) { |
| 125 | + elem.cacheClassElem = elem.className; |
| 126 | + elem.cacheClassTarget = target.className; |
| 127 | + target.className = "code-highlighted"; |
| 128 | + elem.className = "code-highlighted"; |
| 129 | + } |
| 130 | + } |
| 131 | + function CodeHighlightOff(elem, id) |
| 132 | + { |
| 133 | + var target = document.getElementById(id); |
| 134 | + if(elem.cacheClassElem) |
| 135 | + elem.className = elem.cacheClassElem; |
| 136 | + if(elem.cacheClassTarget) |
| 137 | + target.className = elem.cacheClassTarget; |
| 138 | + } |
| 139 | +/*]]>*///--> |
| 140 | +</script> |
| 141 | +</head> |
| 142 | +<body> |
| 143 | +<div id="content"> |
| 144 | +<h1 class="title">锁的设计模型</h1> |
| 145 | +<p> |
| 146 | +宣传一下我的qq群:412052579。里面有一些计算机相关的资料,不定期有人开讲。 |
| 147 | +</p> |
| 148 | + |
| 149 | +<p> |
| 150 | +锁是资源争用模型里面,排队模型的实现方式之一。建议先去了解一下资源争用模型, |
| 151 | +<a href="https://github.com/wyycode/java/blob/master/java/concurrency.org">临时blog地址</a> |
| 152 | +</p> |
| 153 | + |
| 154 | +<p> |
| 155 | +一个锁的设计要考虑的包含如下几个方面: |
| 156 | +</p> |
| 157 | +<ol class="org-ol"> |
| 158 | +<li>抽象资源状态的标志位 |
| 159 | +</li> |
| 160 | +<li>对标志位的原子复合操作 |
| 161 | +</li> |
| 162 | +<li>对争用者行为的控制,包括暂停和恢复 |
| 163 | +</li> |
| 164 | +<li>对争用者的暂存功能 |
| 165 | +</li> |
| 166 | +</ol> |
| 167 | + |
| 168 | +<p> |
| 169 | +先理解我说的这四点 |
| 170 | +</p> |
| 171 | + |
| 172 | +<p> |
| 173 | +然后我再说分布式锁 |
| 174 | +</p> |
| 175 | + |
| 176 | +<p> |
| 177 | +原子复合操作就是底层工具提供的原子操作的原语 |
| 178 | +</p> |
| 179 | + |
| 180 | +<p> |
| 181 | +比如jvm给java提供的 cas |
| 182 | +</p> |
| 183 | + |
| 184 | +<p> |
| 185 | +cpu给系统提供的内存屏障 |
| 186 | +</p> |
| 187 | + |
| 188 | +<p> |
| 189 | +硬件到系统,系统到vm,vm到语言,单机到分布式 |
| 190 | +</p> |
| 191 | + |
| 192 | +<p> |
| 193 | +都相当于底层为上层提供支持 |
| 194 | +</p> |
| 195 | + |
| 196 | +<p> |
| 197 | +不要傻傻的跟我从语言一步到硬件 |
| 198 | +</p> |
| 199 | + |
| 200 | +<p> |
| 201 | +系统依赖硬件提供的原子操作(数据结构)构建出系统级原语给vm/c语言用,vm依赖系统提供的原语构造出原子操作(数据结构)给java使用 |
| 202 | +</p> |
| 203 | + |
| 204 | +<p> |
| 205 | +单机到分布式也是一样的 |
| 206 | +</p> |
| 207 | + |
| 208 | +<p> |
| 209 | +锁要实现的功能就是要操作排队 |
| 210 | +</p> |
| 211 | + |
| 212 | +<p> |
| 213 | +操作的划分,在现有的系统中都是以线程为单位的 |
| 214 | +</p> |
| 215 | + |
| 216 | +<p> |
| 217 | +那么锁要实现的就是让线程排队 |
| 218 | +</p> |
| 219 | + |
| 220 | +<p> |
| 221 | +排队是做什么呢?我们讲一下生活中的排队 |
| 222 | +</p> |
| 223 | + |
| 224 | +<p> |
| 225 | +先来的操作资源,后来的人在 依次 等待,等前面的人 完成之后,恢复操作 |
| 226 | +</p> |
| 227 | + |
| 228 | +<p> |
| 229 | +这句话里有四个重点词语分别是 |
| 230 | +</p> |
| 231 | + |
| 232 | +<p> |
| 233 | +依次,等待,完成之后,恢复 |
| 234 | +</p> |
| 235 | + |
| 236 | +<p> |
| 237 | +隐含的一个点就是完成之后怎么通知等待者去操作资源的 |
| 238 | +</p> |
| 239 | + |
| 240 | +<p> |
| 241 | +我们来说一下这四个关键词 |
| 242 | +</p> |
| 243 | + |
| 244 | +<p> |
| 245 | +完成之后描述的是资源状态 |
| 246 | +</p> |
| 247 | + |
| 248 | +<p> |
| 249 | +在锁的设计中,我们一般用一个数字来抽象资源状态 |
| 250 | +</p> |
| 251 | + |
| 252 | +<p> |
| 253 | +比如0是空闲,1是被占用 |
| 254 | +</p> |
| 255 | + |
| 256 | +<p> |
| 257 | +依次是要保证线程先来后到的顺序 |
| 258 | +</p> |
| 259 | + |
| 260 | +<p> |
| 261 | +等待呢,是指不占用cpu |
| 262 | +</p> |
| 263 | + |
| 264 | +<p> |
| 265 | +恢复是从排队的队列中唤醒下一个线程 |
| 266 | +</p> |
| 267 | + |
| 268 | +<p> |
| 269 | +jvm是怎么按照这四点来实现一个锁的呢? |
| 270 | +</p> |
| 271 | + |
| 272 | +<p> |
| 273 | +首先用一个state字段抽象资源状态,这个字段是volatile的 |
| 274 | +</p> |
| 275 | + |
| 276 | +<p> |
| 277 | +然后,利用LockSupport.park功能实现线程等待 |
| 278 | +</p> |
| 279 | + |
| 280 | +<p> |
| 281 | +将等待的线程放置到CLH队列里 |
| 282 | +</p> |
| 283 | + |
| 284 | +<p> |
| 285 | +当占用资源的线程使用完成之后,会把state设置为空闲状态,并且利用LockSupport.unpark唤醒下一个线程 |
| 286 | +</p> |
| 287 | + |
| 288 | +<p> |
| 289 | +马上讲分布式锁 |
| 290 | +</p> |
| 291 | + |
| 292 | +<p> |
| 293 | +这就是jvm的单机锁 |
| 294 | +</p> |
| 295 | + |
| 296 | +<p> |
| 297 | +分布式锁与单机锁没有区别,只是资源不再是只存在单机中 |
| 298 | +</p> |
| 299 | + |
| 300 | +<p> |
| 301 | +也就是说,不是只有单机的线程会争用资源, 其他机器的线程也会争用资源 |
| 302 | +</p> |
| 303 | + |
| 304 | +<p> |
| 305 | +场景是,一个资源在多机共享 |
| 306 | +</p> |
| 307 | + |
| 308 | +<p> |
| 309 | +根据以上四点 |
| 310 | +</p> |
| 311 | + |
| 312 | +<p> |
| 313 | +我们需要一个多机都能读写的state数据 |
| 314 | +</p> |
| 315 | + |
| 316 | +<p> |
| 317 | +比如用redis来存这个state |
| 318 | +</p> |
| 319 | + |
| 320 | +<p> |
| 321 | +然后,就跟单机一个实现线程等待,排队,唤醒 |
| 322 | +</p> |
| 323 | + |
| 324 | +<p> |
| 325 | +只是这个抽象的状态由多机的线程共同使用了而已 |
| 326 | +</p> |
| 327 | + |
| 328 | +<p> |
| 329 | +所以还是要先理解争用的资源是什么,争用者的范围是什么 |
| 330 | +</p> |
| 331 | + |
| 332 | +<p> |
| 333 | +如果争用者范围只是单机的,那么就可以用单机的一个state来抽象争用资源 |
| 334 | +</p> |
| 335 | + |
| 336 | +<p> |
| 337 | +如果范围是分布式的, 就需要用一个多机都能读写的state来抽象资源状态设计锁 |
| 338 | +</p> |
| 339 | + |
| 340 | +<p> |
| 341 | +其他的三点,因为都是jvm的线程,所以,都可以利用jvm的原子操作设计 |
| 342 | +</p> |
| 343 | + |
| 344 | +<p> |
| 345 | +所以,所谓的分布式锁,只是争用者范围扩展了而已 |
| 346 | +</p> |
| 347 | + |
| 348 | +<p> |
| 349 | +没什么特别的 |
| 350 | +</p> |
| 351 | +</div> |
| 352 | +<div id="postamble" class="status"> |
| 353 | +<p class="author">Author: 王月阳</p> |
| 354 | +<p class="date">Created: 2017-10-12 周四 10:36</p> |
| 355 | +<p class="creator"><a href="http://www.gnu.org/software/emacs/">Emacs</a> 24.5.1 (<a href="http://orgmode.org">Org</a> mode 8.2.10)</p> |
| 356 | +<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p> |
| 357 | +</div> |
| 358 | +</body> |
| 359 | +</html> |
0 commit comments