修正信号量

来源:互联网 发布:傲剑紫霞升级数据大全 编辑:程序博客网 时间:2024/04/30 06:07

现在考虑Semaphore.java。看起来我们能通过给三个方法加上 synchronized标记,

来修正这个问题,就像这样:

 

//: c13:SynchronizedSemaphore.java

// Colliding over shared resources

 

public class SynchronizedSemaphoreextendsSemaphore

{

private      volatile        int semaphore = 0;

public     synchronized      boolean available() {

return semaphore == 0;


 

 

 

  }

public synchronized void acquire() { ++semaphore; }

public synchronized void release() { --semaphore; }

public InvariantState invariant() {

intval = semaphore;

if(val== 0 || val == 1)

return      new InvariantOK();

else

return new InvariantFailure(newInteger(val));

  }

public     static       void main(String[] args)              throws

Exception {

   SynchronizedSemaphore sem =new

SynchronizedSemaphore();

newSemaphoreTester(sem);

newSemaphoreTester(sem);

newInvariantWatcher(sem).join();

  }

///:~

 

首先,SynchronizedSemaphore类就显得很奇怪:它是从 Semaphore类继承而来,且

所有被重载的方法都标记为 synchronized,但这些方法的基类版本却不是。Java 并不

允许你在重载的时候改变方法的签名,但这却没有产生出错信息。这是因为 synchronized

关键字不属于方法签名的一部分,所以你才能把它加进来,而它也并不局限于重载。

 

从Semaphore类继承的原因是为了重用SemaphoreTester类。当你运行程序的时候你会

发现程序还是会产生InvariantFailure错误。

 

为什么会失败呢?当线程检测到Semaphore可用时,即调用available( )并且返回为真

的时候,对象上的锁已经被释放。这时,另一个线程可能会冲进来,并在前一个线程增加

semaphore值的时候抢先增加。同时,前一个线程还在假设Semaphore对象是可用的,所

以会继续向前并盲目的进入acquire()方法,这就使对象处于不稳定的状态。这只不过

是并发编程首要规则的又一次教训而已:永远不要做任何假设。

 

这个问题的唯一解决方案是,把测试可用性操作和获取操作作为一个单一的原子操作,这

也就是synchronized关键字与对象的锁协作所共同提供的功能。也就是说,Java的锁和

synchronized关键字属于内置的信号量机制,所以你不必自己再去发明一个。


原创粉丝点击