一、使用AQS重写自己的锁代码示例
package com.xz.thread.t10;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @description: 使用AQS重写自己的锁示例
* 1、定义一个MyLock类,实现Lock, 说明MyLock已经是一个锁.
* 2、定义一个继承AQS同步器的AqsSyn类,重写独占方式的锁
* 3、MyLock类的获取锁或者释放锁交由AqsSyn同步器去完成,
* 因此,再使用同步器重写MyLock类里面的所有方法
* @author: xz
*/
public class MyLock implements Lock {
private AqsSyn aqsSyn =new AqsSyn();
//定义一个继承AQS同步器的方法,可以重写独占模式或者共享模式的方法,此处lz重写独占模式的方法
private class AqsSyn extends AbstractQueuedSynchronizer{
//试图在独占模式下获取对象状态。
@Override
protected boolean tryAcquire(int arg) {
/**
* 如果第一个线程进来,可以拿到锁,因此我们可以返回true
* 如果第二个线程进来,拿不到锁,返回false,
* 有种特例,如果当前进来的线程和占用排它锁的线程是同一个线程(重入),则允许可以拿到锁,但是要更新状态值
* */
int state = getState();//获取锁的状态
if(state==0) {//如果状态等于0 ,无状态(初始状态)
if(compareAndSetState(0,arg)) {// 自动设置同步状态到给定的更新,如果状态等于0 ,将状态设置为arg
setExclusiveOwnerThread(Thread.currentThread());//设置占用排它锁的线程是当前线程
return true;
}
}else if(getExclusiveOwnerThread()==Thread.currentThread()){// 重入
setState(state+1);//更新状态值
return true;
}
return false;
}
//试图设置状态来反映独占模式下的一个释放。
@Override
protected boolean tryRelease(int arg) {
//锁的获取和释放肯定是一一对应的,那么调用此方法的线程一定是当前线程,如果不是抛出异常
if(Thread.currentThread()!=getExclusiveOwnerThread()) {
throw new RuntimeException();
}
int state = getState()-arg;
boolean flag = false;
if(state==0) {//状态为0,释放锁
setExclusiveOwnerThread(null);//设置占用排它锁的线程为空
flag = true;
}
setState(state);
return flag;
}
Condition newCondition() {
return new ConditionObject();
}
}
@Override
public void lock() {
aqsSyn.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
aqsSyn.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return aqsSyn.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return aqsSyn.tryAcquireNanos(1,unit.toNanos(time));
}
@Override
public void unlock() {
aqsSyn.release(1);
}
@Override
public Condition newCondition() {
return aqsSyn.newCondition();
}
}
二、测试使用AQS重写自己的锁是否产生线程安全性问题
1、代码
package com.xz.thread.t10;
/**
* @description: 测试使用AQS重写自己的锁是否产生安全性问题
* @author: xz
*/
public class Test {
private int value;
private MyLock myLock =new MyLock();
public int getValue(){
myLock.lock();
try {
Thread.sleep(100);
return value++;
} catch (InterruptedException e) {
throw new RuntimeException();
}finally {
myLock.unlock();
}
}
public static void main(String[] args) {
Test t =new Test();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName()+"----"+t.getValue());
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName()+"===="+t.getValue());
}
}
}).start();
}
}
2、输出结果 3、结论
- 在使用AQS重写自己的锁情况下,同一个实例中多个线程获取的值不存在相同的情况。因此没有产生线程安全性问题。
1、代码
package com.xz.thread.t10;
/**
* @description: 测试使用AQS重写自己的锁是否可重入
* @author: xz
*/
public class Test2 {
private MyLock myLock =new MyLock();
public void a(){
myLock.lock();
System.out.println("执行了a方法");
b();
myLock.unlock();
}
public void b(){
myLock.lock();
System.out.println("执行了b方法");
myLock.unlock();
}
public static void main(String[] args) {
Test2 t =new Test2();
new Thread(new Runnable() {
@Override
public void run() {
t.a();
}
}).start();
}
}
2、输出结果 3、结论
-
因为使用了AQS重写自己的锁,所以既能执行a方法,又能执行b方法;
-
如果不使用重入锁,只会执行a方法;