相关博客:
https://blog.csdn.net/Dongguabai/article/details/84178241
https://blog.csdn.net/Dongguabai/article/details/82691626
https://blog.csdn.net/Dongguabai/article/details/82461675
https://blog.csdn.net/Dongguabai/article/details/84142037
在JDK文档中有这么一段描述:
应该将子类定义为非公共内部帮助器类,可用它们来实现其封闭类的同步属性。类 AbstractQueuedSynchronizer 没有实现任何同步接口。而是定义了诸如
acquireInterruptibly(int)
之类的一些方法,在适当的时候可以通过具体的锁和相关同步器来调用它们,以实现其公共方法
接下来照葫芦画瓢。
先不实现重入功能,只实现锁的功能:
package com.example.demoClient;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @author Dongguabai
* @date 2018/11/17 14:52
*/
public class MyLock implements Serializable, Lock {
private final MySync sync;
public MyLock() {
this.sync = new MySync();
}
//照抄
@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();
}
static class MySync extends AbstractQueuedSynchronizer {
@Override
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//第一个线程进来,可以获得锁
//第二个线程进来,拿不到锁
//获取状态
int state = getState();
if (state == 0) { //初始值,第一次进来
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
return false;
}
@Override
protected final boolean tryRelease(int releases) {
//首先要注意的是锁的获取和释放需要一一对应,也就是说调用此方法的线程一定是当前线程
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
//其实这里releases就是1
int c = getState() - releases;
boolean free = false;
if (c == 0) {
setExclusiveOwnerThread(null);
free = true;
}
setState(c);
return free;
}
//照抄
final Condition newCondition() {
return new ConditionObject();
}
}
}
再来测试之前提到过的线程不安全的例子(具体可参看:https://blog.csdn.net/Dongguabai/article/details/83931773):
package com.example.demoClient;
/**
* @author Dongguabai
* @date 2018/11/10 16:53
*/
public class Demo3 {
MyLock myLock = new MyLock();
private int value = 1;
public static void main(String[] args) {
Demo3 demo3 = new Demo3();
new Thread(() -> {
while (true) {
System.out.println("用户" + Thread.currentThread().getName() + "买了第" + demo3.increamentAndGet() + "张票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "张三").start();
new Thread(() -> {
while (true) {
System.out.println("用户" + Thread.currentThread().getName() + "买了第" + demo3.increamentAndGet() + "张票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "王五").start();
new Thread(() -> {
while (true) {
System.out.println("用户" + Thread.currentThread().getName() + "买了第" + demo3.increamentAndGet() + "张票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "李四").start();
}
//synchronized
public int increamentAndGet() {
myLock.lock();
value++;
myLock.unlock();
return value;
}
}
测试通过:
再来测试重入:
package com.example.demoClient;
/**
* @author Dongguabai
* @date 2018/11/16 15:58
*/
public class Test {
private MyLock lock = new MyLock();
public void a(){
lock.lock();
System.out.println("aaaaaaaaaaaaaaaaaaaaaa");
b();
lock.unlock();
}
public void b(){
lock.lock();
System.out.println("bbbbbbbbbbbbbbbbbbbbbb");
lock.unlock();
}
public static void main(String[] args) {
Test test = new Test();
new Thread(()->{
test.a();
},"xxxxxxxxxxxxxxxxxxx").start();
}
}
运行结果:
查看线程状态:
线程处于WAITING状态。简单分析为什么线程会处于WAITING状态:
原因主要跟state有关(具体可参看https://blog.csdn.net/Dongguabai/article/details/84178241或者https://blog.csdn.net/Dongguabai/article/details/82461675):
结合代码:
第一次进来state=0且将state设置为了1,后续直接就return false了。相当于代码的意思是第一个线程进来,可以获得到锁,但是第二个线程进来的时候要分为两种情况,第一种是如果当前进来的线程和当前独占的线程是同一个线程的话,是需要放行并且记录状态的,如果不是,直接return false。
修改后的锁:
package com.example.demoClient;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @author Dongguabai
* @date 2018/11/17 14:52
*/
public class MyLock implements Serializable, Lock {
private final MySync sync;
public MyLock() {
this.sync = new MySync();
}
//照抄
@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();
}
static class MySync extends AbstractQueuedSynchronizer {
@Override
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//第一个线程进来,可以获得锁
//第二个线程进来,拿不到锁,如果当前进来的线程和当前独占的线程是同一个线程的话,是需要放行并且记录状态的,如果不是,直接return false
//获取状态
int state = getState();
if (state == 0) { //初始值,第一次进来
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) {
//这里没有线程安全问题,直接相加
int nextc = state + acquires;
if (nextc < 0) {// overflow
throw new Error("Maximum lock count exceeded");
}
//这里没有线程安全问题,直接设置
setState(nextc);
return true;
}
return false;
}
@Override
protected final boolean tryRelease(int releases) {
//首先要注意的是锁的获取和释放需要一一对应,也就是说调用此方法的线程一定是当前线程
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
//其实这里releases就是1
int c = getState() - releases;
boolean free = false;
if (c == 0) {
setExclusiveOwnerThread(null);
free = true;
}
setState(c);
return free;
}
//照抄
final Condition newCondition() {
return new ConditionObject();
}
}
}
再来测试重入问题:
正常运行。