在Doug lea的那本着名的《Java并发编程—设计原则与模式》英文名 Concurrent Programming in Java;: Design Principles and Patterns Second Edition书中提到可以用信号量Semaphore实现互斥锁Mutex虽然java中是通过synchronize关键字提供锁并用这个基础设施实现信号量的在有的系统中只有信号量这一原语锁是通过信号量实现的代码如下
importncurrentSemaphore; publicclassMutex{ privateSemaphores=newSemaphore(); publicvoidacquire()throwsInterruptedException{ sacquire(); } publicvoidrelease(){ srelease(); } publicbooleanattempt(intms)throwsInterruptedException{ returnstryAcquire(ms); } } 上面的代码只能在java中编译通过因为Semaphore是在java中才提供的我在读上面的代码时有疑问因为如果错误的连续调用release两次然后两个线程都调用acquire岂不是这两个线程都可以同时运行从而违背了互斥锁的定义?为了证明我的猜测写了如下的代码 publicclassTestMutex{ publicstaticvoidmain(String[]args)throwsInterruptedException{ Mutexmutex=newMutex(); mutexacquire(); mutexrelease(); mutexrelease(); newMyThread(mutex)start(); newMyThread(mutex)start(); } } classMyThreadextendsThread{ privateMutexmutex; publicMyThread(Mutexmutex){ thismutex=mutex; } publicvoidrun(){ try{ mutexacquire(); }catch(InterruptedExceptione){ thrownewRuntimeException(e); } for(inti=;i<;i++){ Systemoutprint(i); if(i%==){ try{ Threadsleep(); }catch(InterruptedExceptione){ eprintStackTrace(); } } } mutexrelease(); } } 该程序的输出如下
从而证实了我的猜测 作为对比下面是采用synchronized关键字的互斥锁方案
publicclassTestLock{ publicstaticvoidmain(String[]args)throwsInterruptedException{ newMyThread()start(); newMyThread()start(); } } classMyThreadextendsThread{ publicvoidrun(){ synchronized(TestLockclass){ for(inti=;i<;i++){ Systemoutprint(i); if(i%==){ try{ Threadsleep(); }catch(InterruptedExceptione){ eprintStackTrace(); } } } } } } 该程序的输出如下
可见两个线程确实互斥运行 这个问题产生的原因是虽然在Mutex的定义中privateSemaphores=newSemaphore()也就是该信号量的初始permits是但是在此后每次调用release方法都会导致permits加一如果能限制permits最大值最小值那就是真正的Mutex了 |