———————————————————————今天不闲聊—————————————————————————————
第十一章:线程
第四节:synchronized与同步
首先,我们来看一段代码:
1 package cc.openhome;
2
3 import java.util.ArrayList;
4
5 public class ArrayListDemo {
6 public static void main(String[] args) {
7 final ArrayList list = new ArrayList();
8 Thread t1 = new Thread() {
9 public void run() {
10 while(true) {
11 list.add(1);
12 }
13 }
14 };
15 Thread t2 = new Thread() {
16 public void run() {
17 while(true) {
18 list.add(2);
19 }
20 }
21 };
22 t1.start();
23 t2.start();
24 }
25 }
在这个例子里,我们建立了两个线程,分别在while循环中对同一个ArrayList实例进行add()。如果尝试执行程序,“有可能”会发生ArrayIndexOutOfBoundsException异常。为什么会这样呢?因为如果t1、t2两个线程同时调用add()方法,假设t1执行add()已经到了list[next++]=0该行,这个时候CPU排班器将t1置回Runnable状态,将t2置入Running状态,而t2执行add()已完成list[next++]=0行的执行,这个时候next刚好等于数组长度。如果这时候CPU排班器将t2置回Runnable状态,将t1置入Running状态,于是t1开始list[next++]=0行,因为next刚好等于数组长度,结果就发生了ArrayIndexOutOfBoundsException。
我们通常把这种情况称之为线程存取同一对象相同资源时所引发的竞速情况(Race condition),就这个例子来说,是因为t1、t2能够同时存取next,使得next在巧合情况下,脱离了原本应该管控的条件,我们称ArrayList这样的类为不具备线程安全的类。线程安全(Thread-safe)。
那么,如何解决这样的问题呢?我们可以在add()方法上使用synchronized关键字。例如:
1 ...
2 public synchronized void add (Object o){
3 if(next == list.length){
4 list = Arrays.copyOf(list,list.length*2);
5 }
6 list[next++]=0;
7 }
8 ...
只要这样,就能保证不会再看到ArrayIndexOutOfBoundsException异常了,这是为什么呢?因为每个对象都会有个内部锁(IntrinsicLock),或称为监控锁(Monitor lock)。被标示为synchronized的区块将会被监控,任何线程要执行该区块都必须先获取指定的对象锁。如果A线程已经获得了对象锁而开始执行synchronized区块,B线程也想执行synchronized区块,会因无法取得对象锁而进入等待锁状态。
线程在Running状态时,若因尝试执行synchronized区块而进入Blocked,在取得锁定之后,会先回到Runnable状态,等待CPU调度再进去Running状态。
(关于使用volatile、死锁等问题,我们在第二轮复习的时候再补充。)
现在先简单说一下死锁的造成原因。死锁的发生必须具备以下四个必要条件。
1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
其实关于多线程还有很多东西,不过由于进度的原因,这一部分会在下一季再继续,敬请期待。
——————————————下面是我将近4个月前写的一篇东西,有兴趣的朋友可以看看————————————————
大家都要好好的
今晚跟高中同学吃饭,他跟我说他最近的不如意,感情上遭遇挫折,学业上找不到兴趣。我一边听着,一边跟他说我的故事。
我跟他说某某某老是跟我说TA实习应聘到终面等通知的事,之前会有点烦,觉得TA是在炫耀在嘲笑我没找到。可是现在,当TA打电话兴奋地告诉我说要履行诺言请我吃饭的时候,我真的很开心。不是因为那一顿饭,而是我为TA的顺利感到高兴,从心底里感到高兴。我又跟TA说某某某跟我学的是一个专业,TA实习到了一家业内一流的企业,而我之前可能会有点嫉妒,可是现在,当TA打趣我找不到实习的时候,我不会觉得TA是在讽刺我,而会从心里认为TA付出那么多我所能目睹的努力理应得到这些东西,he deserves。
与此同时,我也在好好努力。
自从决定要学J2EE开发之后,我下载了很多相关的电子书开始看,学习的兴趣跟投入的时间都跟以前大不相同。我在微博上开始关注一些业内的微博,每天睡前都会刷新看看有没有我感兴趣或对我有帮助的内容,然后转发留档。从微博上知道了有道云笔记这个应用,试用之后一发不可收拾地喜欢上了它,用它来同步自己做的笔记和好文章好资料的网页摘要。学习开始有了眉目,各种有利的因素开始形成体系。就这样,我开始用自己喜欢的方式做着自认为有意义的事情,不会觉得苦。一点点的进步,让我看到了自己的成长,很开心。考完期末之后,我马上投入到了某公司的笔试准备当中,跟随自己的节奏,一步一步稳稳地走。
最后,我送那个喝了一瓶啤酒的同学回到宿舍楼下,心里想着:希望你尽快好起来。
毕业季,在人人网上看到许多狂欢庆祝的照片,忍不住想象自己毕业的时候会是什么个样子。这种离别的气氛让我有点感伤,也让我愈发珍惜剩下不多的时光。真的,朋友,希望你们也一样,身边的同学还有一年不到的时间就要各奔东西了。不要把时间浪费在嫉妒那些比自己好的同学身上,他们找到好实习好工作或者出国进名校都付出了一般人难以想象的努力,或许拉不下面子向他们请教,但是我们可以看看他们平时所做的一切,体会什么叫一分耕耘一分收获。他们都是我们的同学,是跟我们一起三年即将四年的兄弟姐妹,在最后的时刻,不应该为他们感到高兴,不应该祝福他们过得越来越好吗?
更不要瞧不起那些看起来不如自己的同学。每个班里,总有那么几个喜欢玩游戏喜欢看网络小说喜欢不务正业的学生。或许他们成绩很差,很难找到工作,甚至连毕业都成问题。在他们废寝忘食的时候,善意地提醒他们要记得吃饭别熬夜免得猝死,考试前多说几句复习要紧、考完再玩、老师很严格的话。在他们遭遇考试挂科或面试挫折的时候,好言安慰几句,给几个合理的建议让他们没那么难受,不要逃避而是继续努力。这些都是我们所轻而易举能做到的事情,更何况他们是跟我们住在同一间宿舍的同学。天南地北,能到一起,住一起一千多天,不容易。是缘分,就得珍惜。
虽然离毕业还有一段时间,但我已经开始在心里默默想着:
大家都要好好的。
————————————————————————第二十三天——————————————————————
快要毕业了,心里还是蛮不舍得的。
1.今天的内容比较少,可能明天的也不会很多,不过后天至少是double的篇幅。这一季最后的几天,要冲刺一下才行。
2.今天是我的二十二岁生日,我只想对自己说一句:
3.你要好好的。