今天实现一个可以自定义N个线程共享的共享锁,代码一部分来自《Java并发编程的艺术》。
如果想具体理解Java锁的底层原理,我非常建议大家购买这本书。
实现的功能是,提供一个构造方法,可以接受一个int值来确定具体可以几个线程同时共享锁,锁实例化之后就不能修改该属性了。
方法的思路是来自《Java并发编程的艺术》这本书中关于锁的介绍,我只是稍加修改和完善。
实现上底层依赖了Java本身的并发队列AbstractQueuedSynchronizer,通过在锁中内置一个该对象的子类来实现底层的CAS更新,响应中断,超时等待等功能。
具体代码如下(GitHub地址):
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class ShareLock implements Lock {
private Sync sync;
public ShareLock(int count) {
if (count <= 0) {
throw new IllegalArgumentException("share count must large than zero!");
}
sync = new Sync(count);
}
@Override
public void lock() {
sync.acquireShared(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquireShared(1) >= 0;
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireSharedNanos(1,unit.toNanos(time));
}
@Override
public void unlock() {
sync.releaseShared(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
public Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
//内部类继承自AbstractQueuedSynchronizer,由它来实现关键同步操作。
private static class Sync extends AbstractQueuedSynchronizer {
Sync(int count) {
setState(count);
}
@Override
protected int tryAcquireShared(int arg) {
int current = getState();
int newCount = current - arg;
if (newCount < 0 || compareAndSetState(current, newCount)) {
return newCount;
}
return -1;
}
@Override
protected boolean tryReleaseShared(int arg) {
int current = getState();
int newCount = current + arg;
return compareAndSetState(current, newCount);
}
final ConditionObject newCondition() {
return new ConditionObject();
}
}
}
测试代码如下:
@Test
public void testSharedLock() {
final ShareLock shareLock = new ShareLock(5);
class Worker extends Thread {
@Override
public void run() {
while (true) {
shareLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\tget lock");
SleepUtil.second(1);
} finally {
shareLock.unlock();
}
}
}
}
for (int i = 0; i < 20; i++) {
Worker worker = new Worker();
worker.setDaemon(true);
worker.start();
}
System.out.println("在等待队列里面的线程:");
shareLock.getQueuedThreads().forEach(System.out::println);
}
测试代码运行结果:
具体的实现就完成了,本博客抱着学习的态度编写,希望可以给大家带来帮助。