原理:
编写工具类,通过反射获取unsafe类。
package com.lzq.util;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class UnsafeInstance {
//获取Unsafe对象
public static Unsafe reflectGetUnsafe() {
//通过反射机制获取到Unsafe类
Field field = null;
try {
field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- 编写AQS
package com.lzq.AQS;
import java.util.concurrent.ConcurrentLinkedQueue;
import com.lzq.util.UnsafeInstance;
import sun.misc.Unsafe;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.LockSupport;
public class AQS {
//定义状态,0未获得锁,1代表已经获得锁。
private int state = 0;
//定义当前获取锁的线程。
private Thread lockHolder;
//定义队列
private ConcurrentLinkedQueue<Thread> waiters = new ConcurrentLinkedQueue<>();
//尝试获得锁
public boolean acquire(){
//获取锁状态
int state = getState();
Thread thread = Thread.currentThread();
/* 如果是锁状态为0,或者队列里面没有等待线程,或者当前线程为队列中第一个线程,
那么就去尝试改变state,如果改变成功,那么就抢到锁,否则就是抢不到锁*/
if(state == 0 && (waiters == null || thread == waiters.peek()) && compareAndSwapState(0,1)){
//抢到锁,设置当前线程为锁的拥有者
setLockHolder(thread);
return true;
}
return false;
}
//上锁
public void lock(){
//上锁成功
if(acquire()){
return;
}
//获取锁失败,将锁加入到waiter队列中。
Thread thread = Thread.currentThread();
waiters.add(thread);
//自旋,知道拿到锁为止
while(true){
//如果当前线程为队列的第一个元素,并且获得锁
if(thread == waiters.peek() && acquire()){
//当前线程退出队列
waiters.poll();
return;
}
//获取锁失败,那么就让出cpu使用权。
LockSupport.park(thread);
}
}
//解锁
public void unlock(){
Thread thread = Thread.currentThread();
//如果当前线程是否是锁的拥有者,那么才可以解锁
if(thread == getLockHolder() && getState() == 1 && compareAndSwapState(1,0)){
//设置当前线程为空
setLockHolder(null);
//唤醒队列的第一个线程,然后该线程会去自旋获取锁。
Thread first = waiters.peek();
if(first != null){
LockSupport.unpark(first);
}
}
}
public final boolean compareAndSwapState(int except,int update){
return unsafe.compareAndSwapInt(this,stateOffset,except,update);
}
//通过反射机制获取到Unsafe对象
private static final Unsafe unsafe = UnsafeInstance.reflectGetUnsafe();
//在内存的偏移量值,因为CAS种需要此参数
private static long stateOffset;
static {
try {
//找到state对象在内存中的偏移量
stateOffset = unsafe.objectFieldOffset(AQS.class.getDeclaredField("state"));
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public Thread getLockHolder() {
return lockHolder;
}
public void setLockHolder(Thread lockHolder) {
this.lockHolder = lockHolder;
}
}
- 编写测试类
package com.lzq.TEST;
import com.lzq.AQS.AQS;
import java.util.ArrayList;
import java.util.List;
public class AQSTest {
//共享变量
private static int count = 0;
//创建手写的锁
private static AQS syn = new AQS();
//线程执行的方法
public void m() {
syn.lock();
for (int i = 0; i < 100000; i++) {
count++;
}
syn.unlock();
}
public static void main(String[] args) {
AQSTest t=new AQSTest();
List<Thread> threads=new ArrayList<>();
//创建10个线程,并执行m方法
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m,"thread-"+i));
}
threads.forEach((o)->o.start());
threads.forEach((o)->{
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(count);
}
}
不加锁:
加锁: