/
3b701acb.html
333 lines (303 loc) · 68.6 KB
/
3b701acb.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<!DOCTYPE html><html class="theme-next gemini use-motion" lang="zh-Hans"><head><meta name="generator" content="Hexo 3.8.0"><meta name="google-site-verification" content="SJDgyqjBwkGnbvvQE_jdQKhgkQfRh7WhtS0-E3egoyk"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="theme-color" content="#222"><meta name="viewport" content="width=device-width"><script src="/lib/pace/pace.min.js?v=1.0.2"></script><link href="/lib/pace/pace-theme-minimal.min.css?v=1.0.2" rel="stylesheet"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css"><link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4"><link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4"><link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4"><link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222"><meta name="keywords" content="Java,线程安全,并发编程,锁机制,同步,synchronized,锁,"><link rel="alternate" href="/atom.xml" title="从入门到放弃" type="application/atom+xml"><meta name="description" content="简介上篇【从入门到放弃-Java】并发编程-线程安全中,我们了解到,可以通过加锁机制来保护共享对象,来实现线程安全。 synchronized是java提供的一种内置的锁机制。通过synchronized关键字同步代码块。线程在进入同步代码块之前会自动获得锁,并在退出同步代码块时自动释放锁。内置锁是一种互斥锁。 本文来深入学习下synchronized。 使用同步方法同步非静态方法12345678"><meta name="keywords" content="Java,线程安全,并发编程,锁机制,同步,synchronized,锁"><meta property="og:type" content="article"><meta property="og:title" content="【从入门到放弃-Java】并发编程-锁-synchronized"><meta property="og:url" content="https://nc2era.com/3b701acb.html"><meta property="og:site_name" content="从入门到放弃"><meta property="og:description" content="简介上篇【从入门到放弃-Java】并发编程-线程安全中,我们了解到,可以通过加锁机制来保护共享对象,来实现线程安全。 synchronized是java提供的一种内置的锁机制。通过synchronized关键字同步代码块。线程在进入同步代码块之前会自动获得锁,并在退出同步代码块时自动释放锁。内置锁是一种互斥锁。 本文来深入学习下synchronized。 使用同步方法同步非静态方法12345678"><meta property="og:locale" content="zh-Hans"><meta property="og:image" content="https://nc2era.com/3b701acb/1.jpg"><meta property="og:image" content="https://nc2era.com/3b701acb/2.jpg"><meta property="og:image" content="https://nc2era.com/3b701acb/3.jpg"><meta property="og:updated_time" content="2019-07-21T14:30:56.873Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="【从入门到放弃-Java】并发编程-锁-synchronized"><meta name="twitter:description" content="简介上篇【从入门到放弃-Java】并发编程-线程安全中,我们了解到,可以通过加锁机制来保护共享对象,来实现线程安全。 synchronized是java提供的一种内置的锁机制。通过synchronized关键字同步代码块。线程在进入同步代码块之前会自动获得锁,并在退出同步代码块时自动释放锁。内置锁是一种互斥锁。 本文来深入学习下synchronized。 使用同步方法同步非静态方法12345678"><meta name="twitter:image" content="https://nc2era.com/3b701acb/1.jpg"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",scheme:"Gemini",version:"5.1.4",sidebar:{position:"left",display:"post",offset:12,b2t:!1,scrollpercent:!1,onmobile:!1},fancybox:!0,tabs:!0,motion:{enable:!0,async:!1,transition:{post_block:"fadeIn",post_header:"slideDownIn",post_body:"slideDownIn",coll_header:"slideLeftIn",sidebar:"slideUpIn"}},duoshuo:{userId:"0",author:"博主"},algolia:{applicationID:"",apiKey:"",indexName:"",hits:{per_page:10},labels:{input_placeholder:"Search for Posts",hits_empty:"We didn't find any results for the search: ${query}",hits_stats:"${hits} results found in ${time} ms"}}}</script><link rel="canonical" href="https://nc2era.com/3b701acb.html"><title>【从入门到放弃-Java】并发编程-锁-synchronized | 从入门到放弃</title><script type="text/javascript">var _hmt=_hmt||[];!function(){var e=document.createElement("script");e.src="https://hm.baidu.com/hm.js?7f0f37da8af427b455867492ca709c92";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)}()</script></head><body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans"><div class="container sidebar-position-left page-post-detail"><div class="headband"></div><header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="header-inner"><div class="site-brand-wrapper"><div class="site-meta"><div class="custom-logo-site-title"><a href="/" class="brand" rel="start"><span class="logo-line-before"><i></i></span> <span class="site-title">从入门到放弃</span><span class="logo-line-after"><i></i></span></a></div><h1 class="site-subtitle" itemprop="description">从入门到放弃-程序员进阶之路</h1></div><div class="site-nav-toggle"> <button><span class="btn-bar"></span><span class="btn-bar"></span><span class="btn-bar"></span></button></div></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i><br> 首页</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i><br> 标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i><br> 分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i><br> 归档</a></li><li class="menu-item menu-item-search"><a href="javascript:;" class="popup-trigger"><i class="menu-item-icon fa fa-search fa-fw"></i><br> 搜索</a></li></ul><div class="site-search"><div class="popup search-popup local-search-popup"><div class="local-search-header clearfix"><span class="search-icon"><i class="fa fa-search"></i></span><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span><div class="local-search-input-wrapper"> <input autocomplete="off" placeholder="搜索..." spellcheck="false" type="text" id="local-search-input"></div></div><div id="local-search-result"></div></div></div></nav></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><div class="post-block"><link itemprop="mainEntityOfPage" href="https://nc2era.com/3b701acb.html"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="AloofJr"><meta itemprop="description" content><meta itemprop="image" content="/images/avatar.gif"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="从入门到放弃"></span><header class="post-header"><h2 class="post-title" itemprop="name headline">【从入门到放弃-Java】并发编程-锁-synchronized</h2><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i></span> <span class="post-meta-item-text">发表于</span> <time title="创建于" itemprop="dateCreated datePublished" datetime="2019-07-14T17:38:00+08:00">2019-07-14</time></span> <span class="post-comments-count"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-comment-o"></i></span><a href="/3b701acb.html#comments" itemprop="discussionUrl"><span class="post-comments-count valine-comment-count" data-xid="/3b701acb.html" itemprop="commentCount"></span></a></span> <span class="post-meta-divider">|</span><span class="page-pv"><i class="fa fa-file-o"></i> 浏览<span class="busuanzi-value" id="busuanzi_value_page_pv"></span></span><div class="post-wordcount"><span class="post-meta-item-icon"><i class="fa fa-file-word-o"></i></span> <span class="post-meta-item-text">字数统计:</span> <span title="字数统计">2.3k</span> <span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-clock-o"></i></span> <span class="post-meta-item-text">阅读时长 ≈</span> <span title="阅读时长">10</span></div></div></header><div class="post-body" itemprop="articleBody"><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>上篇<a href="https://nc2era.com/3567c420.html">【从入门到放弃-Java】并发编程-线程安全</a>中,我们了解到,可以通过加锁机制来保护共享对象,来实现线程安全。</p><p>synchronized是java提供的一种内置的锁机制。通过synchronized关键字同步代码块。线程在进入同步代码块之前会自动获得锁,并在退出同步代码块时自动释放锁。内置锁是一种互斥锁。</p><p>本文来深入学习下synchronized。</p><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><h3 id="同步方法"><a href="#同步方法" class="headerlink" title="同步方法"></a>同步方法</h3><h4 id="同步非静态方法"><a href="#同步非静态方法" class="headerlink" title="同步非静态方法"></a>同步非静态方法</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Synchronized</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> count;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">add1</span><span class="params">()</span> </span>{</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> Synchronized sync = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Thread thread1 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> Thread thread2 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync.add1();</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> thread1.start();</span><br><span class="line"> thread2.start();</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结果符合预期:synchronized作用于非静态方法,锁定的是实例对象,如上所示锁的是sync对象,因此线程能够正确的运行,count的结果总会是20000。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Synchronized</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> count;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">add1</span><span class="params">()</span> </span>{</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> Synchronized sync = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Synchronized sync1 = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Thread thread1 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> Thread thread2 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync1.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> thread1.start();</span><br><span class="line"> thread2.start();</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结果不符合预期:如上所示,作用于非静态方法,锁的是实例化对象,因此当sync和sync1同时运行时,还是会出现线程安全问题,因为锁的是两个不同的实例化对象。</p><h4 id="同步静态方法"><a href="#同步静态方法" class="headerlink" title="同步静态方法"></a>同步静态方法</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Synchronized</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> count;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">add1</span><span class="params">()</span> </span>{</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">add11</span><span class="params">()</span> </span>{</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> Synchronized sync = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Synchronized sync1 = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Thread thread1 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> Synchronized.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> Thread thread2 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> Synchronized.add11();</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> thread1.start();</span><br><span class="line"> thread2.start();</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结果符合预期:锁静态方法时,锁的是类对象。因此在不同的线程中调用add1和add11依然会得到正确的结果。</p><h3 id="同步代码块"><a href="#同步代码块" class="headerlink" title="同步代码块"></a>同步代码块</h3><h4 id="锁当前实例对象"><a href="#锁当前实例对象" class="headerlink" title="锁当前实例对象"></a>锁当前实例对象</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Synchronized</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> count;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">add1</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">synchronized</span> (<span class="keyword">this</span>) {</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">add11</span><span class="params">()</span> </span>{</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> Synchronized sync = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Synchronized sync1 = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Thread thread1 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> Thread thread2 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync1.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> thread1.start();</span><br><span class="line"> thread2.start();</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结果不符合预期:当synchronized同步方法块时,锁的是实例对象时,如上示例在不同的实例中调用此方法还是会出现线程安全问题。</p><h4 id="锁其它实例对象"><a href="#锁其它实例对象" class="headerlink" title="锁其它实例对象"></a>锁其它实例对象</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Synchronized</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> count;</span><br><span class="line"> <span class="keyword">public</span> String lock = <span class="keyword">new</span> String();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">add1</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">synchronized</span> (lock) {</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">add11</span><span class="params">()</span> </span>{</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> Synchronized sync = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Synchronized sync1 = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Thread thread1 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> Thread thread2 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync1.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> thread1.start();</span><br><span class="line"> thread2.start();</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> System.out.println(count);</span><br><span class="line"></span><br><span class="line"> System.out.println(sync.lock == sync1.lock);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> <img src="/3b701acb/1.jpg"><p>结果不符合预期:当synchronized同步方法块时,锁的是其它实例对象时,如上示例在不同的实例中调用此方法还是会出现线程安全问题。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Synchronized</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> count;</span><br><span class="line"> <span class="keyword">public</span> String lock = <span class="string">""</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">add1</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">synchronized</span> (lock) {</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">add11</span><span class="params">()</span> </span>{</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> Synchronized sync = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Synchronized sync1 = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Thread thread1 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> Thread thread2 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync1.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> thread1.start();</span><br><span class="line"> thread2.start();</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> System.out.println(count);</span><br><span class="line"></span><br><span class="line"> System.out.println(sync.lock == sync1.lock);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> <img src="/3b701acb/2.jpg"><p>结果符合预期:当synchronized同步方法块时,锁的虽然是其它实例对象时,但已上实例中,因为String = “” 是存放在常量池中的,实际上锁的还是相同的对象,因此是线程安全的</p><h4 id="锁类对象"><a href="#锁类对象" class="headerlink" title="锁类对象"></a>锁类对象</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Synchronized</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> count;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">add1</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">synchronized</span> (Synchronized.class) {</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">add11</span><span class="params">()</span> </span>{</span><br><span class="line"> count++;</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> Synchronized sync = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Synchronized sync1 = <span class="keyword">new</span> Synchronized();</span><br><span class="line"> Thread thread1 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> Thread thread2 = <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i< <span class="number">10000</span>; i++) {</span><br><span class="line"> sync1.add1();</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> thread1.start();</span><br><span class="line"> thread2.start();</span><br><span class="line"> Thread.sleep(<span class="number">1000</span>);</span><br><span class="line"> System.out.println(count);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>结果符合预期:当synchronized同步方法块时,锁的是类对象时,如上示例在不同的实例中调用此方法是线程安全的。</p><h2 id="锁机制"><a href="#锁机制" class="headerlink" title="锁机制"></a>锁机制</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Synchronized</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> count;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> <span class="keyword">synchronized</span> (Synchronized.class) {</span><br><span class="line"> count++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>使用javap -v Synchronized.class反编译class文件。</p> <img src="/3b701acb/3.jpg"><p><strong>可以看到synchronized实际上是通过monitorenter和monitorexit来实现锁机制的。同一时刻,只能有一个线程进入监视区。从而保证线程的同步。</strong></p><p>正常情况下在指令4进入监视区,指令14退出监视区然后指令15直接跳到指令23 return</p><p>但是在异常情况下异常都会跳转到指令18,依次执行到指令20monitorexit释放锁,防止出现异常时未释放的情况。<br>这其实也是synchronized的优点:无论代码执行情况如何,都不会忘记主动释放锁。</p><p>想了解Monitors更多的原理可以<a href="https://www.artima.com/insidejvm/ed2/threadsynch.html" rel="external nofollow noopener noreferrer" target="_blank">点击查看</a></p><h2 id="锁升级"><a href="#锁升级" class="headerlink" title="锁升级"></a>锁升级</h2><p>因为monitor依赖操作系统的Mutex lock实现,是一个比较重的操作,需要切换系统至内核态,开销非常大。因此在jdk1.6引入了偏向锁和轻量级锁。<br>synchronized有四种状态:无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁。</p><h3 id="无锁"><a href="#无锁" class="headerlink" title="无锁"></a>无锁</h3><p>没有对资源进行锁定,所有线程都能访问和修改。但同时只有一个线程能修改成功</p><h3 id="偏向锁"><a href="#偏向锁" class="headerlink" title="偏向锁"></a>偏向锁</h3><p>在锁竞争不强烈的情况下,通常一个线程会多次获取同一个锁,为了减少获取锁的代价 引入了偏向锁,会在java对象头中记录获取锁的线程的threadID。</p><ul><li>当线程发现对象头的threadID存在时。判断与当前线程是否是同一线程。</li><li>如果是则不需要再次加、解锁。</li><li>如果不是,则判断threadID是否存活。不存活:设置为无锁状态,其他线程竞争设置偏向锁。存活:查找threadID堆栈信息判断是否需要继续持有锁。需要持有则升级threadID线程的锁为轻量级锁。不需要持有则撤销锁,设置为无锁状态等待其它线程竞争。</li></ul><p>因为偏向锁的撤销操作还是比较重的,导致进入安全点,因此在竞争比较激烈时,会影响性能,可以使用-XX:-UseBiasedLocking=false禁用偏向锁。</p><h3 id="轻量级锁"><a href="#轻量级锁" class="headerlink" title="轻量级锁"></a>轻量级锁</h3><p>当偏向锁升级为轻量级锁时,其它线程尝试通过CAS方式设置对象头来获取锁。</p><ul><li>会先在当前线程的栈帧中设置Lock Record,用于存储当前对象头中的mark word的拷贝。</li><li>复制mark word的内容到lock record,并尝试使用cas将mark word的指针指向lock record</li><li>如果替换成功,则获取偏向锁</li><li>替换不成功,则会自旋重试一定次数。</li><li>自旋一定次数或有新的线程来竞争锁时,轻量级锁膨胀为重量级锁。</li></ul><h4 id="CAS"><a href="#CAS" class="headerlink" title="CAS"></a>CAS</h4><p>CAS即compare and swap(比较并替换)。是一种乐观锁机制。通常有三个值</p><ul><li>V:内存中的实际值</li><li>A:旧的预期值</li><li>B:要修改的新值<br>即V与A相等时,则替换V为B。即内存中的实际值与我们的预期值相等时,则替换为新值。</li></ul><p>CAS可能遇到ABA问题,即内存中的值为A,变为B后,又变为了A,此时A为新值,不应该替换。<br>可以采取:A-1,B-2,A-3的方式来避免这个问题</p><h3 id="重量级锁"><a href="#重量级锁" class="headerlink" title="重量级锁"></a>重量级锁</h3><p>自旋是消耗CPU的,因此在自旋一段时间,或者一个线程在自旋时,又有新的线程来竞争锁,则轻量级锁会膨胀为重量级锁。<br>重量级锁,通过monitor实现,monitor底层实际是依赖操作系统的mutex lock(互斥锁)实现。<br>需要从用户态,切换为内核态,成本比较高</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文我们一起学习了</p><ul><li>synchronized的几种用法:同步方法、同步代码块。实际上是同步类或同步实例对象。</li><li>锁升级:无锁、偏向锁、轻量级锁、重量级锁以及其膨胀过程。</li></ul><p>synchronized作为内置锁,虽然帮我们解决了线程安全问题,但是带来了性能的损失,因此一定不能滥用。使用时请注意同步块的作用范围。通常,作用范围越小,对性能的影响也就越小(注意权衡获取、释放锁的成本,不能为了缩小作用范围,而频繁的获取、释放)。</p></div><footer class="post-footer"><div class="post-tags"> <a href="/tags/Java/" rel="tag"># Java</a> <a href="/tags/线程安全/" rel="tag"># 线程安全</a> <a href="/tags/并发编程/" rel="tag"># 并发编程</a> <a href="/tags/锁机制/" rel="tag"># 锁机制</a> <a href="/tags/同步/" rel="tag"># 同步</a> <a href="/tags/synchronized/" rel="tag"># synchronized</a> <a href="/tags/锁/" rel="tag"># 锁</a></div><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/3567c420.html" rel="next" title="【从入门到放弃-Java】并发编程-线程安全"><i class="fa fa-chevron-left"></i> 【从入门到放弃-Java】并发编程-线程安全</a></div><span class="post-nav-divider"></span><div class="post-nav-prev post-nav-item"> <a href="/304643e5.html" rel="prev" title="【从入门到放弃-Java】并发编程-JUC-ConcurrentHashMap">【从入门到放弃-Java】并发编程-JUC-ConcurrentHashMap<i class="fa fa-chevron-right"></i></a></div></div></footer></div></article><div class="post-spread"></div></div></div><div class="comments" id="comments"></div></div><div class="sidebar-toggle"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span><span class="sidebar-toggle-line sidebar-toggle-line-middle"></span><span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div><aside id="sidebar" class="sidebar"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> 文章目录</li><li class="sidebar-nav-overview" data-target="site-overview-wrap"> 站点概览</li></ul><section class="site-overview-wrap sidebar-panel"><div class="site-overview"><div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person"><p class="site-author-name" itemprop="name">AloofJr</p><p class="site-description motion-element" itemprop="description"></p></div><nav class="site-state motion-element"><div class="site-state-item site-state-posts"> <a href="/archives/"><span class="site-state-item-count">47</span> <span class="site-state-item-name">日志</span></a></div><div class="site-state-item site-state-categories"> <a href="/categories/index.html"><span class="site-state-item-count">1</span> <span class="site-state-item-name">分类</span></a></div><div class="site-state-item site-state-tags"> <a href="/tags/index.html"><span class="site-state-item-count">50</span> <span class="site-state-item-name">标签</span></a></div></nav><div class="feed-link motion-element"><a href="/atom.xml" rel="alternate"><i class="fa fa-rss"></i> RSS</a></div><div class="links-of-author motion-element"><span class="links-of-author-item"><a href="https://github.com/AloofJr" target="_blank" title="GitHub" rel="external nofollow noopener noreferrer"><i class="fa fa-fw fa-github"></i> GitHub</a></span></div></div></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#简介"><span class="nav-number">1.</span> <span class="nav-text">简介</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#使用"><span class="nav-number">2.</span> <span class="nav-text">使用</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#同步方法"><span class="nav-number">2.1.</span> <span class="nav-text">同步方法</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#同步非静态方法"><span class="nav-number">2.1.1.</span> <span class="nav-text">同步非静态方法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#同步静态方法"><span class="nav-number">2.1.2.</span> <span class="nav-text">同步静态方法</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#同步代码块"><span class="nav-number">2.2.</span> <span class="nav-text">同步代码块</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#锁当前实例对象"><span class="nav-number">2.2.1.</span> <span class="nav-text">锁当前实例对象</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#锁其它实例对象"><span class="nav-number">2.2.2.</span> <span class="nav-text">锁其它实例对象</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#锁类对象"><span class="nav-number">2.2.3.</span> <span class="nav-text">锁类对象</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#锁机制"><span class="nav-number">3.</span> <span class="nav-text">锁机制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#锁升级"><span class="nav-number">4.</span> <span class="nav-text">锁升级</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#无锁"><span class="nav-number">4.1.</span> <span class="nav-text">无锁</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#偏向锁"><span class="nav-number">4.2.</span> <span class="nav-text">偏向锁</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#轻量级锁"><span class="nav-number">4.3.</span> <span class="nav-text">轻量级锁</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#CAS"><span class="nav-number">4.3.1.</span> <span class="nav-text">CAS</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#重量级锁"><span class="nav-number">4.4.</span> <span class="nav-text">重量级锁</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#总结"><span class="nav-number">5.</span> <span class="nav-text">总结</span></a></li></ol></div></div></section></div></aside></div></main><footer id="footer" class="footer"><div class="footer-inner"><div class="copyright">© <span itemprop="copyrightYear">2020</span><span class="with-love"><i class="fa fa-user"></i></span> <span class="author" itemprop="copyrightHolder">AloofJr</span> <span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-area-chart"></i></span> <span class="post-meta-item-text">Site words total count:</span> <span title="Site words total count">79.4k</span></div><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script><div class="busuanzi-count"><script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><span class="site-uv"><i class="fa fa-user"></i><span class="busuanzi-value" id="busuanzi_value_site_uv"></span></span><span class="site-pv"><i class="fa fa-eye"></i><span class="busuanzi-value" id="busuanzi_value_site_pv"></span></span></div></div></footer><div class="back-to-top"><i class="fa fa-arrow-up"></i></div></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script><script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script><script src="//unpkg.com/valine/dist/Valine.min.js"></script><script type="text/javascript">
var GUEST = ['nick','mail','link'];
var guest = 'nick,mail';
guest = guest.split(',').filter(item=>{
return GUEST.indexOf(item)>-1;
});
new Valine({
el: '#comments' ,
verify: true,
notify: true,
appId: 'AtTFeTEomwo5ADIQTR8YFRcL-gzGzoHsz',
appKey: 'vKO8qLF0TzyALMhWTxgQ7GPh',
placeholder: '欢迎各路大神交流指正!',
avatar:'mm',
guest_info:guest,
pageSize:'10' || 10,
});
</script><script type="text/javascript">
// Popup Window;
var isfetched = false;
var isXml = true;
// Search DB path;
var search_path = "search.xml";
if (search_path.length === 0) {
search_path = "search.xml";
} else if (/json$/i.test(search_path)) {
isXml = false;
}
var path = "/" + search_path;
// monitor main search box;
var onPopupClose = function (e) {
$('.popup').hide();
$('#local-search-input').val('');
$('.search-result-list').remove();
$('#no-result').remove();
$(".local-search-pop-overlay").remove();
$('body').css('overflow', '');
}
function proceedsearch() {
$("body")
.append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
.css('overflow', 'hidden');
$('.search-popup-overlay').click(onPopupClose);
$('.popup').toggle();
var $localSearchInput = $('#local-search-input');
$localSearchInput.attr("autocapitalize", "none");
$localSearchInput.attr("autocorrect", "off");
$localSearchInput.focus();
}
// search function;
var searchFunc = function(path, search_id, content_id) {
'use strict';
// start loading animation
$("body")
.append('<div class="search-popup-overlay local-search-pop-overlay">' +
'<div id="search-loading-icon">' +
'<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
'</div>' +
'</div>')
.css('overflow', 'hidden');
$("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');
$.ajax({
url: path,
dataType: isXml ? "xml" : "json",
async: true,
success: function(res) {
// get the contents from search data
isfetched = true;
$('.popup').detach().appendTo('.header-inner');
var datas = isXml ? $("entry", res).map(function() {
return {
title: $("title", this).text(),
content: $("content",this).text(),
url: $("url" , this).text()
};
}).get() : res;
var input = document.getElementById(search_id);
var resultContent = document.getElementById(content_id);
var inputEventFunction = function() {
var searchText = input.value.trim().toLowerCase();
var keywords = searchText.split(/[\s\-]+/);
if (keywords.length > 1) {
keywords.push(searchText);
}
var resultItems = [];
if (searchText.length > 0) {
// perform local searching
datas.forEach(function(data) {
var isMatch = false;
var hitCount = 0;
var searchTextCount = 0;
var title = data.title.trim();
var titleInLowerCase = title.toLowerCase();
var content = data.content.trim().replace(/<[^>]+>/g,"");
var contentInLowerCase = content.toLowerCase();
var articleUrl = decodeURIComponent(data.url);
var indexOfTitle = [];
var indexOfContent = [];
// only match articles with not empty titles
if(title != '') {
keywords.forEach(function(keyword) {
function getIndexByWord(word, text, caseSensitive) {
var wordLen = word.length;
if (wordLen === 0) {
return [];
}
var startPosition = 0, position = [], index = [];
if (!caseSensitive) {
text = text.toLowerCase();
word = word.toLowerCase();
}
while ((position = text.indexOf(word, startPosition)) > -1) {
index.push({position: position, word: word});
startPosition = position + wordLen;
}
return index;
}
indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
});
if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
isMatch = true;
hitCount = indexOfTitle.length + indexOfContent.length;
}
}
// show search results
if (isMatch) {
// sort index by position of keyword
[indexOfTitle, indexOfContent].forEach(function (index) {
index.sort(function (itemLeft, itemRight) {
if (itemRight.position !== itemLeft.position) {
return itemRight.position - itemLeft.position;
} else {
return itemLeft.word.length - itemRight.word.length;
}
});
});
// merge hits into slices
function mergeIntoSlice(text, start, end, index) {
var item = index[index.length - 1];
var position = item.position;
var word = item.word;
var hits = [];
var searchTextCountInSlice = 0;
while (position + word.length <= end && index.length != 0) {
if (word === searchText) {
searchTextCountInSlice++;
}
hits.push({position: position, length: word.length});
var wordEnd = position + word.length;
// move to next position of hit
index.pop();
while (index.length != 0) {
item = index[index.length - 1];
position = item.position;
word = item.word;
if (wordEnd > position) {
index.pop();
} else {
break;
}
}
}
searchTextCount += searchTextCountInSlice;
return {
hits: hits,
start: start,
end: end,
searchTextCount: searchTextCountInSlice
};
}
var slicesOfTitle = [];
if (indexOfTitle.length != 0) {
slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
}
var slicesOfContent = [];
while (indexOfContent.length != 0) {
var item = indexOfContent[indexOfContent.length - 1];
var position = item.position;
var word = item.word;
// cut out 100 characters
var start = position - 20;
var end = position + 80;
if(start < 0){
start = 0;
}
if (end < position + word.length) {
end = position + word.length;
}
if(end > content.length){
end = content.length;
}
slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
}
// sort slices in content by search text's count and hits' count
slicesOfContent.sort(function (sliceLeft, sliceRight) {
if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
return sliceRight.searchTextCount - sliceLeft.searchTextCount;
} else if (sliceLeft.hits.length !== sliceRight.hits.length) {
return sliceRight.hits.length - sliceLeft.hits.length;
} else {
return sliceLeft.start - sliceRight.start;
}
});
// select top N slices in content
var upperBound = parseInt('1');
if (upperBound >= 0) {
slicesOfContent = slicesOfContent.slice(0, upperBound);
}
// highlight title and content
function highlightKeyword(text, slice) {
var result = '';
var prevEnd = slice.start;
slice.hits.forEach(function (hit) {
result += text.substring(prevEnd, hit.position);
var end = hit.position + hit.length;
result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
prevEnd = end;
});
result += text.substring(prevEnd, slice.end);
return result;
}
var resultItem = '';
if (slicesOfTitle.length != 0) {
resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
} else {
resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
}
slicesOfContent.forEach(function (slice) {
resultItem += "<a href='" + articleUrl + "'>" +
"<p class=\"search-result\">" + highlightKeyword(content, slice) +
"...</p>" + "</a>";
});
resultItem += "</li>";
resultItems.push({
item: resultItem,
searchTextCount: searchTextCount,
hitCount: hitCount,
id: resultItems.length
});
}
})
};
if (keywords.length === 1 && keywords[0] === "") {
resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
} else if (resultItems.length === 0) {
resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
} else {
resultItems.sort(function (resultLeft, resultRight) {
if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
return resultRight.searchTextCount - resultLeft.searchTextCount;
} else if (resultLeft.hitCount !== resultRight.hitCount) {
return resultRight.hitCount - resultLeft.hitCount;
} else {
return resultRight.id - resultLeft.id;
}
});
var searchResultList = '<ul class=\"search-result-list\">';
resultItems.forEach(function (result) {
searchResultList += result.item;
})
searchResultList += "</ul>";
resultContent.innerHTML = searchResultList;
}
}
if ('auto' === 'auto') {
input.addEventListener('input', inputEventFunction);
} else {
$('.search-icon').click(inputEventFunction);
input.addEventListener('keypress', function (event) {
if (event.keyCode === 13) {
inputEventFunction();
}
});
}
// remove loading animation
$(".local-search-pop-overlay").remove();
$('body').css('overflow', '');
proceedsearch();
}
});
}
// handle and trigger popup window;
$('.popup-trigger').click(function(e) {
e.stopPropagation();
if (isfetched === false) {
searchFunc(path, 'local-search-input', 'local-search-result');
} else {
proceedsearch();
};
});
$('.popup-btn-close').click(onPopupClose);
$('.popup').click(function(e){
e.stopPropagation();
});
$(document).on('keyup', function (event) {
var shouldDismissSearchPopup = event.which === 27 &&
$('.search-popup').is(':visible');
if (shouldDismissSearchPopup) {
onPopupClose();
}
});
</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script></body></html>