Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 285c141

Browse files
author
wangyueyang
committed
Merge branch 'master' of https://github.com/wyycode/java
2 parents e1cf5fb + a116399 commit 285c141

File tree

2 files changed

+128
-15
lines changed

2 files changed

+128
-15
lines changed

java/concurrency.html

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
55
<head>
66
<title>资源争用模型(泛多线程编程)</title>
7-
<!-- 2017-09-24 日 14:34 -->
7+
<!-- 2017-09-25 一 22:33 -->
88
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
99
<meta name="generator" content="Org-mode" />
1010
<meta name="author" content="王月阳" />
@@ -184,11 +184,10 @@ <h2>Table of Contents</h2>
184184
</li>
185185
<li><a href="#sec-5">5. Java内存模型与资源争用</a>
186186
<ul>
187-
<li><a href="#sec-5-1">5.1. Java内存模型与运行时内存分布,分析被争用的资源</a></li>
187+
<li><a href="#sec-5-1">5.1. 分析被争用的资源</a></li>
188188
<li><a href="#sec-5-2">5.2. Java如何使用不共享内存模型解决线程安全问题</a>
189189
<ul>
190-
<li><a href="#sec-5-2-1">5.2.1. copyOnWriteList</a></li>
191-
<li><a href="#sec-5-2-2">5.2.2. ThreadLocal</a></li>
190+
<li><a href="#sec-5-2-1">5.2.1. ThreadLocal</a></li>
192191
</ul>
193192
</li>
194193
<li><a href="#sec-5-3">5.3. Java如果使用不可变资源模型解决线程安全问题</a>
@@ -489,7 +488,7 @@ <h2 id="sec-5"><span class="section-number-2">5</span> Java内存模型与资源
489488
</p>
490489
</div>
491490
<div id="outline-container-sec-5-1" class="outline-3">
492-
<h3 id="sec-5-1"><span class="section-number-3">5.1</span> Java内存模型与运行时内存分布,分析被争用的资源</h3>
491+
<h3 id="sec-5-1"><span class="section-number-3">5.1</span> 分析被争用的资源</h3>
493492
<div class="outline-text-3" id="text-5-1">
494493
<p>
495494
Java的内存模型主要包含两部分,一部分是主内存,也就是所有java线程共享;另一部分是java线程的本地变量,包含局部变量和共享
@@ -502,23 +501,92 @@ <h3 id="sec-5-1"><span class="section-number-3">5.1</span> Java内存模型与
502501
doServie方法。所以,servlet对象的属性在web编程过程中是被当作共享资源争用的,而doService方法里定义的局部变量是每个线程
503502
私有的。所以,servlet的属性是非线程安全的,需要一定的机制去保证线程安全。
504503
</p>
504+
505+
<p>
506+
业务系统中,我们怎么分析被争用的资源呢?其实是一样的,关键是分析哪些资源是共享的。比如电商系统中账户的金额,比如商品
507+
的数量。这些都是会被不同业务线程争用的资源。下面我们具体分析一下,怎么利用资源争用模型保证数据安全的。
508+
</p>
509+
510+
<p>
511+
<b>*</b> 账户金额问题
512+
在一个电商系统中,账户是会存在同一个时刻有多个操作请求的,比如用户购买商品发生账户扣款的同时也在充值,比如用户同时从
513+
多个不同终端进行购买支付操作,比如用户连续支付多笔订单。在这一系列的业务场景中,我们怎么通过资源争用模型来保证账户金
514+
额的正确呢?
515+
</p>
516+
517+
<p>
518+
首先我们分析账户金额为啥会不正确?假设账户原始金额为100.00元,业务线程A要为账户充值10元,业务线程B要从账户里扣除30元。
519+
业务线程A先查询到账户里有100元,然后中内存中将10元加上,此时内存中的账户是110元,然后发生了线程上下文切换,线程A被挂
520+
起,线程B执行,B也从数据库中读到了账户余额是100元,然后将支付的30元扣除,此时B认为账户余额应该是70元,写入到数据库中。
521+
线程B执行完成,用户正常支付扣款。然后线程A切换执行,又把账户的余额设置成了110元。线程A也正常执行完成,用户充值成功。
522+
可是,此时账户里是110元,但正常情况下,账户里应有100-30+10 = 80元。那么问题出在哪里呢?
523+
</p>
524+
525+
<p>
526+
可以说是线程A不知道线程B已经把账户里的钱改动过了,所以认为它持有的金额是正确的。也可以说是A的操作被B打断了,所以导致
527+
了A的数据不正确。从资源争用的角度看怎么解决问题呢?排队!让线程A和B的操作依次进行,这样就保证数据安全了。怎么排队呢,
528+
用一个状态值表明账户是否被占用,占用的时候是不允许其他线程操作的。这就相当于用一个互斥量来抽象资源状态,空闲状态的资
529+
源才能被操作,否则线程就要等待。这是不是就是我们通常理解的锁呀。如果是单机,我们可以用java的锁来实现这个互斥量;如果
530+
是分布式系统,我们可以使用redis或者zookeeper提供的原子操作实现的分布式锁来抽象资源状态,进而实现对不同线程的互斥操作。
531+
</p>
532+
533+
<p>
534+
另一种排队方案是什么呢?上面的方案是通过锁实现的排队,我们还可以认为的让所有的操作排队,比如依次只处理一个对账户的写
535+
操作。怎么实现呢?让所有对同一个账户的操作都放到一个队列里面,只有一个消费者线程从队列里取操作去处理账户金额,这样也
536+
实现了对同一个账户操作的排队。java里常用的锁,比如有synchronized关键字,JUC的Lock实现等。
537+
</p>
538+
539+
<p>
540+
还有一种实现方式是什么呢?就是利用数据库提供的行级锁,为每行账户记录加一个版本号,业务线程操作账户金额时,必须带着之
541+
前查出来的版本号,那线程内部版本号和数据库存的版本号进行对比,相同的才能更新账户数据,否则就失败。这也实现了对账户操
542+
作的排队。这种方式其实就是不保留历史记录的MVCC方式。
543+
</p>
544+
545+
<p>
546+
以上三种方式都通过自己的方式实现里对账户操作的排队,保证了不同业务线程对共享的账户金额的安全操作。前面提到的商品数量
547+
问题也可以通过这三种排队方式去实现数据安全。我们可以大胆的推理,所有的共享资源,都可以通过这三种排队方式实现安全。
548+
</p>
549+
550+
<p>
551+
举的这个例子都是写操作,其实还有独立的读操作,比如商品数量问题,不同用户浏览商品的时候,都是对商品数量的读操作,这种
552+
读操作其实是不互斥的,只有发生写操作的时候,才需要互斥。也就是说资源状态中,被占用又可以分为两种状态,被写占用还是读
553+
占用,写占用的时候其他任何读写线程都不能操作,读占用的时候其他读线程可以操作,但写线程会被阻塞。java里的读写锁,就实
554+
现了对这种场景的抽象。读写锁抽象里共享资源的三个状态,实现里对共享资源操作的排队,保证里共享资源的安全。
555+
</p>
505556
</div>
506557
</div>
507558
<div id="outline-container-sec-5-2" class="outline-3">
508559
<h3 id="sec-5-2"><span class="section-number-3">5.2</span> Java如何使用不共享内存模型解决线程安全问题</h3>
509560
<div class="outline-text-3" id="text-5-2">
510-
</div><div id="outline-container-sec-5-2-1" class="outline-4">
511-
<h4 id="sec-5-2-1"><span class="section-number-4">5.2.1</span> copyOnWriteList</h4>
561+
<p>
562+
除去上面的排队模型,还有什么方式可以解决争用呢?可以让业务线程不争用啊,大家不共享了,自然就不争用了。比如java中常见
563+
的SimpleDateFormat对象如果给多个线程同时使用就会出现格式化的日期不对的情况。为啥不对呢,因为SDF对象的属性被多个线程争
564+
用,导致了多个线程使用的时候资源状态混乱,数据错乱。从不共享的角度怎么解决问题呢?那就为每一个线程分配一个SDF对象,这
565+
样线程之间就不会争用一个SDF对象了,没有了争用,资源就安全了,代码执行就正常了。java中常用的实现方式有两种,一种是每次
566+
使用的时候new一个SDF对象出来,另一种方式是利用java提供的ThreadLocal对象。
567+
</p>
568+
</div>
569+
<div id="outline-container-sec-5-2-1" class="outline-4">
570+
<h4 id="sec-5-2-1"><span class="section-number-4">5.2.1</span> ThreadLocal</h4>
571+
<div class="outline-text-4" id="text-5-2-1">
572+
<p>
573+
ThreadLocal在java中叫做线程封闭。什么意思呢,就是把对象封闭到使用的线程中,不给其他线程用,进而不发生争用,保证线程
574+
安全。怎么实现的呢,大概的模型就是利用一个map对象,key是线程,值是业务对象。每次是通过线程当key获取value的,自然不会
575+
重复。
576+
</p>
512577
</div>
513-
<div id="outline-container-sec-5-2-2" class="outline-4">
514-
<h4 id="sec-5-2-2"><span class="section-number-4">5.2.2</span> ThreadLocal</h4>
515578
</div>
516579
</div>
517-
518580
<div id="outline-container-sec-5-3" class="outline-3">
519581
<h3 id="sec-5-3"><span class="section-number-3">5.3</span> Java如果使用不可变资源模型解决线程安全问题</h3>
520582
<div class="outline-text-3" id="text-5-3">
521-
</div><div id="outline-container-sec-5-3-1" class="outline-4">
583+
<p>
584+
不可变模型相当于是不争用的一个特例。不可变意味着可以任意复制多份到任意线程中,不会争用。可是如果要修改对象的数据怎么
585+
办呢?这个时候就要通过copyOnWrite实现了。copyOnWrite不会修改原对象的数据,而是会原子的复制原对象的数据, 并把新的数据
586+
写到新对象里面,然后返回一个新对象。java通过final关键字实现不可变对象。
587+
</p>
588+
</div>
589+
<div id="outline-container-sec-5-3-1" class="outline-4">
522590
<h4 id="sec-5-3-1"><span class="section-number-4">5.3.1</span> Final关键字</h4>
523591
</div>
524592
<div id="outline-container-sec-5-3-2" class="outline-4">
@@ -591,7 +659,7 @@ <h3 id="sec-7-2"><span class="section-number-3">7.2</span> Zookeeper一主多从
591659
</div>
592660
<div id="postamble" class="status">
593661
<p class="author">Author: 王月阳</p>
594-
<p class="date">Created: 2017-09-24 日 14:34</p>
662+
<p class="date">Created: 2017-09-25 一 22:33</p>
595663
<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>
596664
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
597665
</div>

java/concurrency.org

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,19 +129,64 @@ IO
129129

130130
�ڱ�дjava���뵽ʱ��������ô����������Ӧ�������أ���������Ҫ���ʲô��Ҫ���õ���Դ��Ȼ�����Ƿ��������Դ�����õĹ�����
131131
�ֱ���ʲô����״̬��Ȼ���پ�����ʲô�����������Դ��Ҳ���Ǿ�����ʲô����
132-
** Java�ڴ�ģ��������ʱ�ڴ�ֲ������������õ���Դ
132+
** ���������õ���Դ
133133
Java���ڴ�ģ����Ҫ����������,һ���������ڴ棬Ҳ��������java�̹߳�������һ������java�̵߳ı��ر����������ֲ������͹���
134134
�ڴ��еı������������ģ����ȷ��˵���ˣ���Щ�����õ���Դ��Щ�Dz����õġ���ô��Ӧ��java�����У���ô�����أ������ڵľ�
135135
��������������ݣ����Ƿ����õģ������������ԣ��������ԣ����ߴ���IJ��������п���Ҫ�����߳����á�
136136

137137
���磬���dz����web��̹����У�servlet����ÿ���յ�һ������ͻ����һ���߳�ȥ�������󡣵�ȴ�ǵ���ͬһ��servlet�����
138138
doServie���������ԣ�servlet�����������web��̹������DZ�����������Դ���õģ���doService�����ﶨ��ľֲ�������ÿ���߳�
139139
˽�еġ����ԣ�servlet�������Ƿ��̰߳�ȫ�ģ���Ҫһ���Ļ���ȥ��֤�̰߳�ȫ��
140+
141+
ҵ��ϵͳ�У�������ô���������õ���Դ�أ���ʵ��һ���ģ��ؼ��Ƿ�����Щ��Դ�ǹ����ġ��������ϵͳ���˻��Ľ�������Ʒ
142+
����������Щ���ǻᱻ��ͬҵ���߳����õ���Դ���������Ǿ������һ�£���ô������Դ����ģ�ͱ�֤���ݰ�ȫ�ġ�
143+
144+
*** �˻��������
145+
��һ������ϵͳ�У��˻��ǻ����ͬһ��ʱ���ж����������ģ������û�������Ʒ�����˻��ۿ��ͬʱҲ�ڳ�ֵ�������û�ͬʱ��
146+
�����ͬ�ն˽��й���֧�������������û�����֧����ʶ���������һϵ�е�ҵ�񳡾��У�������ôͨ����Դ����ģ������֤�˻���
147+
�����ȷ�أ�
148+
149+
�������Ƿ����˻����Ϊɶ�᲻��ȷ�������˻�ԭʼ���Ϊ100.00Ԫ��ҵ���߳�AҪΪ�˻���ֵ10Ԫ��ҵ���߳�BҪ���˻���۳�30Ԫ��
150+
ҵ���߳�A�Ȳ�ѯ���˻�����100Ԫ��Ȼ�����ڴ��н�10Ԫ���ϣ���ʱ�ڴ��е��˻���110Ԫ��Ȼ�������߳��������л����߳�A����
151+
���߳�Bִ�У�BҲ�����ݿ��ж������˻������100Ԫ��Ȼ��֧����30Ԫ�۳�����ʱB��Ϊ�˻����Ӧ����70Ԫ��д�뵽���ݿ��С�
152+
�߳�Bִ����ɣ��û�����֧���ۿȻ���߳�A�л�ִ�У��ְ��˻���������ó���110Ԫ���߳�AҲ����ִ����ɣ��û���ֵ�ɹ���
153+
���ǣ���ʱ�˻�����110Ԫ������������£��˻���Ӧ��100-30+10 = 80Ԫ����ô������������أ�
154+
155+
����˵���߳�A��֪���߳�B�Ѿ����˻����Ǯ�Ķ����ˣ�������Ϊ�����еĽ������ȷ�ġ�Ҳ����˵��A�IJ�����B����ˣ����Ե���
156+
��A�����ݲ���ȷ������Դ���õĽǶȿ���ô��������أ��Ŷӣ����߳�A��B�IJ������ν��У������ͱ�֤���ݰ�ȫ�ˡ���ô�Ŷ��أ�
157+
��һ��״ֵ̬�����˻��Ƿ�ռ�ã�ռ�õ�ʱ���Dz����������̲߳����ġ�����൱����һ����������������Դ״̬������״̬����
158+
Դ���ܱ������������߳̾�Ҫ�ȴ������Dz��Ǿ�������ͨ���������ѽ������ǵ��������ǿ�����java������ʵ����������������
159+
�Ƿֲ�ʽϵͳ�����ǿ���ʹ��redis����zookeeper�ṩ��ԭ�Ӳ���ʵ�ֵķֲ�ʽ����������Դ״̬������ʵ�ֶԲ�ͬ�̵߳Ļ��������
160+
161+
��һ���Ŷӷ�����ʲô�أ�����ķ�����ͨ����ʵ�ֵ��Ŷӣ����ǻ�������Ϊ�������еIJ����Ŷӣ���������ֻ����һ�����˻���д
162+
��������ôʵ���أ������ж�ͬһ���˻��IJ������ŵ�һ���������棬ֻ��һ���������̴߳Ӷ�����ȡ����ȥ�����˻�������Ҳ
163+
ʵ���˶�ͬһ���˻��������Ŷӡ�java�ﳣ�õ�����������synchronized�ؼ��֣�JUC��Lockʵ�ֵȡ�
164+
165+
����һ��ʵ�ַ�ʽ��ʲô�أ������������ݿ��ṩ���м�����Ϊÿ���˻���¼��һ���汾�ţ�ҵ���̲߳����˻����ʱ���������֮
166+
ǰ������İ汾�ţ����߳��ڲ��汾�ź����ݿ��İ汾�Ž��жԱȣ���ͬ�IJ��ܸ����˻����ݣ������ʧ�ܡ���Ҳʵ���˶��˻���
167+
�����Ŷӡ����ַ�ʽ��ʵ���Dz�������ʷ��¼��MVCC��ʽ��
168+
169+
�������ַ�ʽ��ͨ���Լ��ķ�ʽʵ������˻��������Ŷӣ���֤�˲�ͬҵ���̶߳Թ������˻����İ�ȫ������ǰ���ᵽ����Ʒ����
170+
����Ҳ����ͨ���������Ŷӷ�ʽȥʵ�����ݰ�ȫ�����ǿ��Դ󵨵����������еĹ�����Դ��������ͨ���������Ŷӷ�ʽʵ�ְ�ȫ��
171+
172+
�ٵ�������Ӷ���д��������ʵ���ж����Ķ�������������Ʒ�������⣬��ͬ�û������Ʒ��ʱ�򣬶��Ƕ���Ʒ�����Ķ�����������
173+
��������ʵ�Dz�����ģ�ֻ�з���д������ʱ�򣬲���Ҫ���⡣Ҳ����˵��Դ״̬�У���ռ���ֿ��Է�Ϊ����״̬����дռ�û��Ƕ�
174+
ռ�ã�дռ�õ�ʱ�������κζ�д�̶߳����ܲ�������ռ�õ�ʱ���������߳̿��Բ�������д�̻߳ᱻ������java��Ķ�д������ʵ
175+
���˶����ֳ����ij��󡣶�д�������ﹲ����Դ������״̬��ʵ����Թ�����Դ�������Ŷӣ���֤�ﹲ����Դ�İ�ȫ��
140176
** Java���ʹ�ò������ڴ�ģ�ͽ���̰߳�ȫ����
141-
*** copyOnWriteList
177+
��ȥ������Ŷ�ģ�ͣ�����ʲô��ʽ���Խ�������أ�������ҵ���̲߳����ð�����Ҳ������ˣ���Ȼ�Ͳ������ˡ�����java�г���
178+
��SimpleDateFormat�������������߳�ͬʱʹ�þͻ���ָ�ʽ�������ڲ��Ե������Ϊɶ�����أ���ΪSDF��������Ա�����߳���
179+
�ã������˶���߳�ʹ�õ�ʱ����Դ״̬���ң����ݴ��ҡ��Ӳ������ĽǶ���ô��������أ��Ǿ�Ϊÿһ���̷߳���һ��SDF������
180+
���߳�֮��Ͳ�������һ��SDF�����ˣ�û�������ã���Դ�Ͱ�ȫ�ˣ�����ִ�о������ˡ�java�г��õ�ʵ�ַ�ʽ�����֣�һ����ÿ��
181+
ʹ�õ�ʱ��newһ��SDF�����������һ�ַ�ʽ������java�ṩ��ThreadLocal����
142182
*** ThreadLocal
143-
183+
ThreadLocal��java�н����̷߳�ա�ʲô��˼�أ����ǰѶ����յ�ʹ�õ��߳��У����������߳��ã��������������ã���֤�߳�
184+
��ȫ����ôʵ�ֵ��أ���ŵ�ģ�;�������һ��map����key���̣߳�ֵ��ҵ�����ÿ����ͨ���̵߳�key��ȡvalue�ģ���Ȼ����
185+
�ظ���
144186
** Java���ʹ�ò��ɱ���Դģ�ͽ���̰߳�ȫ����
187+
���ɱ�ģ���൱���Dz����õ�һ�����������ɱ���ζ�ſ������⸴�ƶ�ݵ������߳��У��������á��������Ҫ�޸Ķ����������ô
188+
���أ����ʱ���Ҫͨ��copyOnWriteʵ���ˡ�copyOnWrite�����޸�ԭ��������ݣ����ǻ�ԭ�ӵĸ���ԭ��������ݣ� �����µ�����
189+
д���¶������棬Ȼ�󷵻�һ���¶���javaͨ��final�ؼ���ʵ�ֲ��ɱ����
145190
*** Final�ؼ���
146191
*** String��
147192

0 commit comments

Comments
 (0)