本文内容参考自Java并发编程之美6.2.3章节。
基于AQS自定义的不可重入锁:
//用AQS自定义同步器——不可重入锁NoReentrantLock
public class NoReentrantLock implements Lock, java.io.Serializable {
//内部类用于完成具体的工作
private static class Sync extends AbstractQueuedSynchronizer {
//锁是否被持有
protected boolean isHeldExclusively(){
return getState() == 1;
}
//如果锁没有被持有(state==0)则尝试获取锁
public boolean tryAcquire(int acquires) {
assert acquires == 1;
if(compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
//尝试释放锁,设置state=0
public boolean tryRelease(int releases) {
assert releases == 1;
if(getState()==0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
//提供条件变量的生成接口
Condition newCondition() {
return new ConditionObject();
}
}
//创建一个Sync实例
private final Sync sync = new Sync();
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1,unit.toNanos(time));
}
@Override
public void unlock() {
sync.release(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
public boolean isLocked() {
return sync.isHeldExclusively();
}
}
消费者生产者模式应用案例:
需要注意的是,两个条件变量notFull和notEmpty的调用不要搞混了(不小心写错出现死锁了,还以为是线程调用有问题,解决了半天。。。)
//生产者消费者模型测试AQS自定义的NoReentrantLock
public class PCTest {
//创建不可重入锁和对应的两个条件变量
final static NoReentrantLock lock = new NoReentrantLock();
final static Condition notFull = lock.newCondition();
final static Condition notEmpty = lock.newCondition();
//定义一个并行的队列和队列的大小(仓库的大小)
final static Queue<String> queue = new LinkedBlockingQueue<>();
final static int queueSize = 10;
private static int id = 0;
private static class producerThread extends Thread {
public void run(){
lock.lock(); //获取独占锁
try {
//如果队列满则等待,这里循环条件判断避免虚假唤醒
while(queue.size()==queueSize){
System.out.println("当前元素已满等待中...");
notEmpty.await(); //条件变量调用await使当前线程阻塞挂起
}
String ele = "ele" + String.valueOf(id++);
System.out.println("生产出一个元素:"+ele);
//生产一个元素到队列
queue.add(ele);
//队列中已经有元素可供消费了,所以用notFull来唤醒消费者线程
notFull.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock(); //释放锁
}
}
}
private static class consumerThread extends Thread {
public void run(){
lock.lock(); //获取独占锁
try {
//如果队列为空则等待
while(queue.size()==0) {
System.out.println("当前没有元素等待中...");
notFull.await();
}
//消费一个元素
String ele = queue.poll();
System.out.println("消费了一个元素: "+ele);
//唤醒生产者线程
notEmpty.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock(); //释放锁
}
}
}
public static void main(String[] args) {
for(int i = 0 ; i < 50 ; i++) {
producerThread producer = new producerThread();
producer.start();
}
for(int i = 0 ; i < 50 ; i++) {
consumerThread consumer = new consumerThread();
consumer.start();
}
}
}