说明
当调用lock时
先竞争资源看看能否获得锁,如果不能则进入队尾进行排队,并且该线程阻塞,以免一直在while循环中运行占用cpu资源
当调用unlock时
进行释放锁操作,先把当前线程的资源释放,然后再唤醒队列的头部
因为当竞争锁时如果直接获得锁,不会进入排队队列,因此释放锁时需要判断
逻辑
代码
功能代码
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
class Node{
private volatile Thread thread= null;
private volatile boolean isWait = false;
Node(Thread thread,boolean isWait){
this.thread = thread;
this.isWait = isWait;
}
public Thread getThread() {
return thread;
}
public boolean isWait() {
return isWait;
}
public void setWait(boolean isWait) {
this.isWait = isWait;
}
}
public class KLock {
//状态标记
private AtomicInteger state = new AtomicInteger(0);
//锁排队队列
private LinkedList<Node> list = new LinkedList<>();
//当前线程
private transient volatile Thread currThread = null;
public void lock() {
//在获取锁之前先进行竞争,如果获得锁立即返回,否则则排队
if(tryAcquire() || acquire(addWait())) {
}
}
public boolean unLock() {
int c = state.get() - 1;
if(Thread.currentThread() != currThread) {
throw new RuntimeException("线程不匹配");
}
boolean flag = false;
if(c == 0) {
currThread = null;
flag = true;
if(list.peek().getThread() == Thread.currentThread()) {
list.pop();
}
}
state.set(c);
if(flag && list.peek() != null) {
//唤醒头部
LockSupport.unpark(list.peek().getThread());
}
return flag;
}
/**
* 加入排队队列
* 当多个线程加入队列时,有可能造成数据漏掉
* 因此需要线程安全操作
* @return
*/
private synchronized Node addWait() {
Node node = new Node(Thread.currentThread(),false);
list.addLast(node);
return node;
}
/**
* 请求资源
* @param node
* @return
*/
private boolean acquire(Node node) {
while(true) {
if(list.peek() == node && tryAcquire()) {
return true;
}
//挂起
if(!node.isWait()) {
node.setWait(true);
LockSupport.park();
}
}
}
/**
* 尝试获取资源
* @return
*/
private boolean tryAcquire() {
//获取锁
Thread thread = Thread.currentThread();
int c = state.get();
if(c == 0) {
//当状态位为0则获取
if(state.compareAndSet(0, 1)) {
currThread = thread;
return true;
}
}
//可重入
if(thread == currThread) {
c = c + 1;
state.set(c);
return true;
}
return false;
}
}
测试代码
/**
* 测试代码
*/
public class Test {
public static void main(String[] args) {
KLock lock = new KLock();
for (int i = 1; i <= 50; i++) {
new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unLock();
}
}
},"线程-" + i).start();
}
}
}