一、自定义同步器
- 原子变量state的含义:state=0表示目前锁没有被线程持有,state=1表示锁已被某线程持有
- 不可重入锁
- 支持条件变量
二、自定义同步器代码实现
public class NonReentrantLock implements Lock, Serializable {
// 内部工具类
private static class Sync extends AbstractQueuedSynchronizer{
//判断是否锁已经被持有
@Override
protected boolean isHeldExclusively(){
return getState()==1;
}
//如果state=0,尝试获取锁
@Override
public boolean tryAcquire(int acquires){
assert acquires==1;
if (compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 尝试释放锁,设置state为0
@Override
protected 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();
}
}
三、生产-消费模型实现
@Slf4j
public class Test<i> {
// 创建不可重入锁
final static NonReentrantLock lock = new NonReentrantLock();
// 创建队列未满的条件变量
final static Condition notFull = lock.newCondition();
// 创建队列非空的条件变量
final static Condition notEmpty = lock.newCondition();
// 创建阻塞队列
final static Queue<Integer> queue = new LinkedBlockingDeque<Integer>();
// 定义阻塞队列大小
final static int queueSize = 10;
public static void main(String[] args) {
// 先把队列填满
Random random = new Random();
// 创建生产者线程
Thread producer = new Thread(new Runnable() {
@Override
public void run() {
// 获取独占锁
lock.lock();
try{
//如果队列已满
while (queue.size() == queueSize){
// 放入条件变量队列
log.info("把生产线程放入条件变量队列...");
notEmpty.await();
}
// 添加元素到队列
int i = random.nextInt(100);
queue.add(i);
log.info("生产线程把元素{}放入队列",i);
//唤醒消费线程
log.info("唤醒消费线程...");
notFull.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 释放锁
lock.unlock();
}
}
});
Thread consumer = new Thread(new Runnable() {
@Override
public void run() {
// 获取独占锁
lock.lock();
try{
// 队列空,放入条件变量等待队列
while (queue.size() == 0){
log.info("把消费线程放入条件变量队列...");
notFull.await();
}
// 消费一个元素
int consEle = queue.poll();
log.info("消费线程消费了元素{}",consEle);
// 唤醒生产线程
notEmpty.signalAll();
log.info("唤醒生产线程...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
producer.start();
consumer.start();
}
}
可以看到,使用条件变量作为同步工具,可以实现生产者/消费者线程的精准唤醒。