从零开始学Java 有关线程的学习总结.docx
《从零开始学Java 有关线程的学习总结.docx》由会员分享,可在线阅读,更多相关《从零开始学Java 有关线程的学习总结.docx(14页珍藏版)》请在冰豆网上搜索。
从零开始学Java有关线程的学习总结
从零开始学Java有关线程的学习总结
1.资源冲突,如果两个线程确实是在修改同一个对象,共享资源的冲突将变得更糟糕,因为这有可能把对象设置成不正确的状态。
通过简单的“信号量”概念引入,把它看作是在两个线程之间进行通信的标志对象。
如果信号量的值是零,则它监控的资源是可用的,但如果这个值是非零的,则被监控的资源不可用,所以线程必须等待。
当资源可用的时候,线程增加信号量的值,然后继续执行这个被监控的资源。
把增加和减少信号量的操作定义为原子操作,这样就可保证两个线程同时访问同一资源的时候不至于冲突。
定义一个简化的信号量:
1.
2.
3.4.class="hljs java has-numbering" style="display:
block; padding:
0px;
5.color:
inherit; box-sizing:
border-box; font-family:
'Source Code Pro',
6.monospace;font-size:
undefined; white-space:
pre; border-top-left-radius:
7.0px; border-top-right-radius:
0px; border-bottom-right-radius:
0px;
8.border-bottom-left-radius:
0px; word-wrap:
normal; background:
9.transparent;"> rgb(0, 0,
10.136); box-sizing:
border-box;">public
11.class="hljs-class" style="box-sizing:
border-box;">12.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
13.border-box;">class
14.style="box-sizing:
border-box; color:
rgb(102, 0,
15.102);">Semaphore
16.style="color:
rgb(0, 0, 136); box-sizing:
17.border-box;">implements
18.style="box-sizing:
border-box; color:
rgb(102, 0,
19.102);">Invariant
{
20. rgb(0, 0, 136);
21.box-sizing:
border-box;">private
22.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
23.border-box;">volatile
24.style="color:
rgb(0, 0, 136); box-sizing:
25.border-box;">int
semaphore = 26.class="hljs-number" style="color:
rgb(0, 102, 102); box-sizing:
27.border-box;">0
;
28. rgb(0, 0, 136);
29.box-sizing:
border-box;">public
30.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
31.border-box;">boolean
32.style="box-sizing:
border-box;">available
(){33.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
34.border-box;">return
semaphore==35.class="hljs-number" style="color:
rgb(0, 102, 102); box-sizing:
36.border-box;">0
;}
37. rgb(0, 0, 136);
38.box-sizing:
border-box;">public
39.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
40.border-box;">void
41.style="box-sizing:
border-box;">acquire
(){ ++semaphore; }
42. rgb(0, 0, 136);
43.box-sizing:
border-box;">public
44.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
45.border-box;">void
46.style="box-sizing:
border-box;">release
(){ --semaphore; }
47. rgb(0, 0, 136);
48.box-sizing:
border-box;">public
InvariantSate 49.class="hljs-title" style="box-sizing:
50.border-box;">invariant
(){
51. rgb(0, 0, 136);
52.box-sizing:
border-box;">int
val = semaphore;
53. rgb(0, 0, 136);
54.box-sizing:
border-box;">if
( val==55.class="hljs-number" style="color:
rgb(0, 102, 102); box-sizing:
56.border-box;">0
||val==57.style="color:
rgb(0, 102, 102); box-sizing:
58.border-box;">1
)
59. rgb(0, 0, 136);
60.box-sizing:
border-box;">return
61.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
62.border-box;">new
InvariantOk();
63. rgb(0, 0, 136);
64.box-sizing:
border-box;">else
65. rgb(0, 0, 136);
66.box-sizing:
border-box;">return
67.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
68.border-box;">new
InvariantFailure(69.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
70.border-box;">new
Integer(val));
71. }
72.}
73.border-box; position:
absolute; width:
50px; top:
0px; left:
0px;
74.margin:
0px; padding:
6px 0px 40px; border-right-width:
1px;
75.border-right-style:
solid; border-right-color:
rgb(221, 221, 221);
76.list-style:
none; text-align:
right; background-color:
rgb(238, 238,
77.238);">
border-box; padding:
0px
78.5px;">1
border-box; padding:
0px
79.5px;">2
border-box; padding:
0px
80.5px;">3
border-box; padding:
0px
81.5px;">4
border-box; padding:
0px
82.5px;">5
border-box; padding:
0px
83.5px;">6
border-box; padding:
0px
84.5px;">7
border-box; padding:
0px
85.5px;">8
border-box; padding:
0px
86.5px;">9
border-box; padding:
0px
87.5px;">10
border-box; padding:
0px
88.5px;">11
border-box; padding:
89.0px 5px;">12
border-box; padding:
90.0px 5px;">13
(其中Invariant接口在博客:
线程测试框架已给出)将semaphore字段设置为volatile,以确保编译器不会对任何读取此值的操作进行优化。
2.解决共享资源竞争,之前说过,可以通过yield()和setPriority()来给线程调度机制提供建议,但这些建议未必会有多大的效果,这取决与你的具体平台和JVM实现。
Java以提供关键字synchronized的形式,为防止资源冲突提供了内置支持。
共享资源一般是以对象的形式存在的内存判断,但也可以是文件,输入/输出端口,或者是打印机。
要控制对共享资源的访问,得先把它包装进一个对象。
然后把所有要访问这个资源的方法标记为synchronized。
即一旦某个线程处于一个标记为synchronized的方法中,那么在这个线程从该方法返回之前,其他所有要调用类中任何标记为synchronized方法的线程都会被阻塞。
每个对象都含有单一的锁(也称为监视器),这个锁本身就是对象的一部分(不用写任何特殊代码)。
当在对象上调用其任意synchronized方法的时候,此对象都被加锁,这时该对象上的其他synchronized方法也只能等到前一个方法调用完并释放了锁之后才能被调用。
针对每一个类也有一个锁(作为类的Class对象的一部分),所以synchronizedstatic方法可以在类的范围内防止对static数据的并发访问。
3.原子操作,即不能被线程调度机制中断的操作;一旦操作开始,那么它一定可以在可能发生的“上下文切换”之前(切换到其他线程执行)执行完毕。
如果问题中的变量类型是除long或double以外的基本类型,对这种变量进行简单的赋值或返回值操作的时候,才算是原子操作。
然而,只要给long或double加上volatile,操作就是原子的了。
注意,在JVM中的自增加操作并不是原子操作,它牵涉到一次读和一次写,所以即使在这样的简单操作中,也为线程出问题提供了空间。
线程工作时,每个线程都可能拥有一个本地栈来维护一些变量的复本,如果把一个变量定义成volatile的,就等于告诉编译器不要做任何优化,直接在主存操作变量。
4.保证上述问题解决,做安全的做法就是使用下面的方法:
1)如果要对类中的某个方法进行同步控制,最好同步所有方法。
如果忽略了其中一个,通常很难确定这么做是否会有负面影响。
2)当去除方法的同步控制时,要非常小心。
通常这么做是基于性能方面的考虑,但在JDK1.3和JDK1.4中,同步控制所需的负担已经大大的减少。
此外,只应在使用性能评价工具证实了同步控制确实是性能瓶颈的时候,才这么做。
5.如果只是希望防止多个线程同时访问方法内部的部分代码而不是防止整个方法,可以使用synchronized关键字来分离代码段,这种方式被称为“临界区”,此时,synchronized被用来指定某个对象,此对象的锁被用来对花括号内的代码进行同步控制:
1.2.class="hljs java has-numbering" style="display:
block; padding:
0px;
3.color:
inherit; box-sizing:
border-box; font-family:
'Source Code Pro',
4.monospace;font-size:
undefined; white-space:
pre; border-top-left-radius:
5.0px; border-top-right-radius:
0px; border-bottom-right-radius:
0px;
6.border-bottom-left-radius:
0px; word-wrap:
normal; background:
7.transparent;">
8.rgb(0, 0, 136); box-sizing:
9.border-box;">synchronized
(syncObject){
10. rgb(136, 0, 0);
11.box-sizing:
border-box;">// This code can be accessed
12. rgb(136, 0, 0);
13.box-sizing:
border-box;">//by only one thread at a time
14. }
15.border-box; position:
absolute; width:
50px; top:
0px; left:
0px;
16.margin:
0px; padding:
6px 0px 40px; border-right-width:
1px;
17.border-right-style:
solid; border-right-color:
rgb(221, 221, 221);
18.list-style:
none; text-align:
right; background-color:
rgb(238, 238,
19.238);">
border-box; padding:
0px
20.5px;">1
border-box; padding:
0px
21.5px;">2
border-box; padding:
0px
22.5px;">3
border-box; padding:
0px
23.5px;">4
使用同步控制块,而不是对整个方法进行同步控制,可以使多个线程访问对象的时间性能得到显著的提高。
要注意的是,当对象中的方法在不同的锁上同步的时候,两个线程可以访问同一个对象:
1.2.class="hljs cs has-numbering" style="display:
block; padding:
0px;
3.color:
inherit; box-sizing:
border-box; font-family:
'Source Code Pro',
4.monospace;font-size:
undefined; white-space:
pre; border-top-left-radius:
5.0px; border-top-right-radius:
0px; border-bottom-right-radius:
0px;
6.border-bottom-left-radius:
0px; word-wrap:
normal; background:
7.transparent;">class DualSynch {
8.
9. rgb(0, 0, 136);
10.box-sizing:
border-box;">private
Object syncObject =
11. rgb(0, 0, 136); box-sizing:
12.border-box;">new
Object();
13.
14. rgb(0, 0, 136);
15.box-sizing:
border-box;">public
synchronized 16.class="hljs-keyword" style="color:
rgb(0, 0, 136); box-sizing:
17.border-box;">void
18.style="box-sizing:
border-box;">f
() {
19. System. rgb(0, 0,
20.136); box-sizing:
border-box;">out
.println(21.class="hljs-string" style="color:
rgb(0, 136, 0); box-sizing:
22.border-box;">"Inside f()"
);
23. rgb(0, 0, 136);
24.box-sizing:
border-box;">try
{
25. Thread.sleep(
26.rgb(0, 102, 102); box-sizing:
border-box;">500
);
27. } rgb(0, 0, 136);
28.box-sizing:
border-box;">catch
(InterruptedException e) {
29.