Java信号量模型需要我们不断的进行学习在学习的时候会有不少的问题阻碍着我们下面我们就来看看同步锁模型只是最简单的同步模型同一时刻只有一个线程能够运行同步代码
有的时候我们希望处理更加复杂的同步模型比如生产者/消费者模型读写同步模型等这种情况下同步锁模型就不够用了我们需要一个新的模型这就是我们要讲述的Java信号量模型
Java信号量模型的工作方式如下线程在运行的过程中可以主动停下来等待某个Java信号量模型的通知这时候该线程就进入到该信号量的待召(Waiting)队列当中等到通知之后再继续运行
很多语言里面同步锁都由专门的对象表示对象名通常叫Monitor同样在很多语言中Java信号量模型通常也有专门的对象名来表示比如MutexSemphore
Java信号量模型要比同步锁模型复杂许多一些系统中信号量甚至可以跨进程进行同步另外一些信号量甚至还有计数功能能够控制同时运行的线程数
我们没有必要考虑那么复杂的模型所有那些复杂的模型都是最基本的模型衍生出来的只要掌握了最基本的信号量模型——等待/通知模型复杂模型也就迎刃而解了
我们还是以Java语言为例Java语言里面的同步锁和Java信号量模型概念都非常模糊没有专门的对象名词来表示同步锁和信号量只有两个同步锁相关的关键字——volatile和synchronized
这种模糊虽然导致概念不清但同时也避免了MonitorMutexSemphore等名词带来的种种误解我们不必执着于名词之争可以专注于理解实际的运行原理
在Java语言里面任何一个Object Reference都可以作为同步锁同样的道理任何一个Object Reference也可以作为Java信号量模型
Object对象的wait()方法就是等待通知Object对象的notify()方法就是发出通知
具体调用方法为
()等待某个Java信号量模型的通知
public static final Object signal = new Object();
… f() {
synchronized(singal) { // 首先我们要获取这个信号量这个信号量同时也是一个同步锁
// 只有成功获取了signal这个信号量兼同步锁之后我们才可能进入这段代码
signalwait(); // 这里要放弃信号量本线程要进入signal信号量的待召(Waiting)队列
// 可怜辛辛苦苦争取到手的Java信号量模型就这么被放弃了
// 等到通知之后从待召(Waiting)队列转到就绪(Ready)队列里面
// 转到了就绪队列中离CPU核心近了一步就有机会继续执行下面的代码了
// 仍然需要把signal同步锁竞争到手才能够真正继续执行下面的代码命苦啊
需要注意的是上述代码中的signalwait()的意思signalwait()很容易导致误解signalwait()的意思并不是说signal开始wait而是说运行这段代码的当前线程开始wait这个signal对象即进入signal对象的待召(Waiting)队列
()发出某个Java信号量模型的通知
… f() {
synchronized(singal) { // 首先我们同样要获取这个信号量同时也是一个同步锁
// 只有成功获取了signal这个信号量兼同步锁之后我们才可能进入这段代码
signalnotify(); // 这里我们通知signal的待召队列中的某个线程
// 如果某个线程等到了这个通知那个线程就会转到就绪队列中
// 但是本线程仍然继续拥有signal这个同步锁本线程仍然继续执行
// 嘿嘿虽然本线程好心通知其他线程
// 但是本线程可没有那么高风亮节放弃到手的同步锁
// 本线程继续执行下面的代码
需要注意的是signalnotify()的意思signalnotify()并不是通知signal这个对象本身而是通知正在等待signal信号量的其他线程
以上就是Object的wait()和notify()的基本用法
实际上wait()还可以定义等待时间当线程在某Java信号量模型的待召队列中等到足够长的时间就会等无可等无需再等自己就从待召队列转移到就绪队列中了
另外还有一个notifyAll()方法表示通知待召队列里面的所有线程这些细节问题并不对大局产生影响