background image

acquire() 时 候 , 第 二 个 线 程 可 能 已 经 调 用 了 acquire() 并 且 增 加 或 者 减 少 了
semaphore 字段的值了,此时的 InvariantWatcher 就可能发现我们的数值违反了我们
制定的约束,不能为非 0 或 1 的值导致程序被停止了。
  大家还要注意:监控程序线程我调用了 join()方法,大家还记得这个方法吗?我在前
面的文章里面介绍过他,加上这个方法会让前面两个线程一直执行直到发生了失败才会
调用我们写的监控程序,join 方法让我们的监控程序不会干扰两个线程的正常运行。
  另外对于 volatile 关键字,这个也不是一句两句说的清楚的,我在后面会做进一步
的解释的。
  上面的实例代码很好的说明了多线程里资源竞争的难题,我学到这里,个人觉得根
本原因还是在线程调度机制 CPU 时间片的随机切换所导致的。
  写上面的实例代码我提到这段代码是模仿信息量的程序的简化版,这个又怎么理解
了?

前面我提到过简单 信号量 的概念,它可以看做两个线程之间的通讯标志对象。假如

信号量的值为 0,则信号量所监控的资源是可用的,如果非 0,则监控资源不可用,那
么其他线程就要等待了,当资源可以被线程使用时候,线程就会增加信号量的值,该线
程然后继续执行并使用这个监控资源,但是其他线程是不能使用监控资源的。我们的例子
就是按这个原理写出来的,属性 semaphore 的初始值是 0,这就是说各个线程在初始
化状态下都是被激活的,线程们的赶紧抢占资源啊。acquire 方法就是给信号量增加值
release 方法释放信号量的数值,available 方法就是对信号量值进行判断,如果值为
0,其他线程就可以抢占资源,不为零其他线程就得等待了。为了很好的演示我写的程序
功能,同时程序里面还加入了我写好的监控程序的代码。

下面我将讲述 java 里如何来解决资源冲突的方案,答案很多人都知道那就是:

synchronized 关键字了,但是大家使用 synchronnied 来解决资源冲突时候,我们想过
它的原理吗?java 到底是运用什么样的算法解决了资源冲突了?

  其实现在所有主流程序解决线程冲突也就是共享资源竞争的问题都是采用一种

叫做序列化共享资源的方案。这个方案的内容就是:在给定的时刻里只准许一个线程访问
共享资源,通常这个是通过在代码前面加上一段能创建一个锁的语句,这就保证了在一
定时间内只有一个线程运行这段代码。锁的作用让不同的线程之间产生相互排斥的效果,

因此这种做法也叫做 互斥量 (mutex).

  Java 也是采用这样的方案来解决线程冲突的问题,在 java 语言里,java 提供

了关键字 synchronized,这个关键字为了防止资源冲突提供了内置支持,换句话说,
当我们使用了 synchronized 关键字时候就告诉了 java 语言,你要帮我解决资源冲突的
问题了。其实 java 语言内部,准确的说法应该是 java

虚拟机内部就是按照 信息量 的原

理解决了这个难题,而内部的行为很像我们写的 Semaphore 类:有一个方法检测信号
量的值,根据值的不同授予线程不同的状态(例如 available 方法),有一个方法会用来增
加信号量的值(例如 acquire 方法),还有一个方法会减少信号量的值(例如 release 方法),
最后当然也有一个监控程序了例如我们写的那样的监控框架。

  我们到底如何使用 synchronized 关键字的,这个问题是不是很搞笑了?我觉得

有时看起来很简单的东西里面所蕴含的精髓可能相当丰富或者这个简单背后有我们难以
理解的高深之处了?因此我要好好谈谈如何使用 synchronized 关键字的问题,当然
synchronized 的用法丰富多彩,我这里只讲用 synchronized 来解决资源共享时候的用
法。这里要声明下,我对 synchronized 的理解还是比较有限的,而且这个关键字其他的
用法我还没深入研究过,自己也写得少,假如后面的内容有些说法过于绝对或者不太正