什么是ReentrantLock ?
ReentrantLock 中文翻译过来就是可重入锁,也就是同一个线程这个锁是可以重复获取的 ,synchronize关键字就是一个隐式的可重入锁。
ReentrantLock 的实现原理
ReentrantLock 是实现了Lock接口使得它能够作为一个锁被使用,同时他还有一个内部类同步器:Sync ,这个类继承了AQS(AbstractQueuedSynchronizer) 类,然后实现AQS里面的模板方法。
这里我们来实现一个独占式的非公平锁
代码骨架搭建
要实现一个 ReentrantLock 首先的实现Lock接口,如下:
class MyReentrantLock implements Lock{
/**
* 加锁方法
*/
@Override
public void lock() {
}
/**
* 中断加锁方法
* @throws InterruptedException
*/
@Override
public void lockInterruptibly() throws InterruptedException {
}
/**
* 尝试加锁
* @return
*/
@Override
public boolean tryLock() {
return false;
}
/**
* 在规定的时间内 尝试加锁
* @param time
* @param unit
* @return
* @throws InterruptedException
*/
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
/**
* 解锁
*/
@Override
public void unlock() {
}
/**
* 线程条件 里面的方法与Object里面的 wait,notify,notifyAll 等方法类似
* @return
*/
@Override
public Condition newCondition() {
return null;
}
}
同时还需要有一个基于AQS的同步器
这里我们在上面的类里面写一个内部类来继承AQS 同时重写下面 的三个方法
到这里这个ReentrantLock 的骨架就已经搭建好了,下面就是实现部分
实现MySync同步器
/**
* 自定义的同步器,仅仅实现
*/
class MySync extends AbstractQueuedSynchronizer {
/**
* 尝试获取锁
* @param acquire
* @return
*/
@Override
protected boolean tryAcquire(int acquire) {
// System.out.println("加锁");
//1、获取当前的线程
Thread thread = Thread.currentThread();
//2、获取当前的线程状态
int state = getState() ;
//3、判断状态是不是为0,如果为0那么就是说明当前锁还未被持有,很有可能有其他线程来获取该锁,那么需要进行CAS操作来设置锁的持有状态
if(state==0 && compareAndSetState(0,acquire)){
//获取锁成功,将持有线程设置为当前线程
setExclusiveOwnerThread(thread);
return true;
//由于是独占式锁,那么如果是当前线程持有的锁那么就只需要设置状态+1就好了
//否则就获取不成功
}else if(thread==getExclusiveOwnerThread()){
if(state+acquire>=0){
setState(state+acquire);
}
return true;
}
return false;
}
/**
* 尝试释放锁
* @param release
* @return
*/
@Override
protected boolean tryRelease(int release) {
//释放锁的时候有两点需要注意
// 1、释放锁的时候肯定是只有持有锁的线程才能来释放锁,所以不需要CAS操作
//2、释放锁的时候只有当状态为0 的时候才算释放完成
Thread thread = Thread.currentThread();
if(thread!=getExclusiveOwnerThread()){
throw new RuntimeException("非法操作");
}
int state = getState()-release;
boolean flag = false;
//如果状态为0
if(state==0){
//将持有线程置空
setExclusiveOwnerThread(null);
flag= true;
}
//设置线程状态
setState(state);
//System.out.println("释放");
return flag;
}
/**
* 是不是当前线程持有锁
* @return
*/
@Override
protected boolean isHeldExclusively() {
return getExclusiveOwnerThread()==Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
}
lock 接口的实现
/**
* 加锁方法
*/
@Override
public void lock() {
this.mySync.acquire(1);
}
/**
* 中断加锁方法
* @throws InterruptedException
*/
@Override
public void lockInterruptibly() throws InterruptedException {
this.mySync.acquireInterruptibly(1);
}
/**
* 尝试加锁
* @return
*/
@Override
public boolean tryLock() {
return this.mySync.tryAcquire(1);
}
/**
* 在规定的时间内 尝试加锁
* @param time
* @param unit
* @return
* @throws InterruptedException
*/
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return this.mySync.tryAcquireNanos(1, unit.toNanos(time));
}
/**
* 解锁
*/
@Override
public void unlock() {
this.mySync.release(1);
}
/**
* 线程条件 里面的方法与Object里面的 wait,notify,notifyAll 等方法类似
* @return
*/
@Override
public Condition newCondition() {
return this.mySync.newCondition();
}
到这里自定义的 ReentrantLock(独占式非公平锁) 就实现完成了
下面我们看一下效果
我们写如下一段测试代码来测试是否成功
其中ThreadFactory 是自定义的一个线程工厂,可以不用传入
public class SelfLock {
public static void main(String[] args) {
final MyReentrantLock reentrantLock = new MyReentrantLock();
final List<Integer> list = new ArrayList<>();
final CountDownLatch countDownLatch = new CountDownLatch(100);
final AtomicReference<MyInteger> atomicI = new AtomicReference<MyInteger>(new MyInteger(4999));
for (int i = 0; i < 5000; i++) {
list.add(i);
}
final MyInteger j = new MyInteger(4999);
/*定义线程工厂 方便bug回溯追踪*/
ThreadFactory customThreadfactory = new ThreadFactoryBuilder()
.setNamePrefix("测试-Thread").setDaemon(false)
.setPriority(Thread.MAX_PRIORITY).build();
/*keepAliveTile 线程最大空闲时间 */
ExecutorService executorService =
new ThreadPoolExecutor(100, 200, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10),customThreadfactory);
long b = System.currentTimeMillis();
for(int i=0;i<100 ;i++){
executorService.execute(() -> {
while (true) {
// int j = atomicInteger.getAndDecrement();
if (j.getIndex() >= 0) {
reentrantLock.lock();
System.out.println("线程"+Thread.currentThread().getName()+"====》" +list.get(j.getIndex()));
j.setIndex(j.getIndex()-1);
reentrantLock.unlock();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
}
countDownLatch.countDown();
}
);
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("耗时---->" + (System.currentTimeMillis() - b));
executorService.shutdown();
}
}
class MyInteger{
int index;
public MyInteger(int i){
this.index=i;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}