Java web项目创建笔记30 之《利用AQS手写一把锁》

和CAS的区别:CAS是不断地去重试,而AQS是放入队列中,释放锁时唤醒其他线程
1、在包com.study.base.util下,添加AqsTryLock.java

package com.study.base.util;

import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

/**
 * 使用aqs手写Lock锁
 * @author user
 *
 */
public class AqsTryLock {

	/**
	 * 区分公平锁和非公平锁
	 */
	private static boolean fairFlag = false;
	
	/**
	 * 锁的状态:0-没有线程获取到锁;1-有线程获取到锁
	 */
	private AtomicInteger lockState = new AtomicInteger(0);
	
	/**
	 * 获取到锁的线程
	 */
	private Thread getLockThread = null;
	
	/**
	 * 存放没有获取到锁的线程的队列
	 */
	private ConcurrentLinkedDeque<Thread> concurrentLinkedDeque = new ConcurrentLinkedDeque<Thread>();
	
	/**
	 * 构造方法
	 * @param fair
	 */
	AqsTryLock(boolean fair) {
		fairFlag = fair;
	}
	
	/**
	 * 获取锁
	 */
	public void lock() {
		acquire();
	}
	
	/**
	 * 释放锁
	 */
	public void unlock() {
		release();
	}
	
	/**
	 * 获取
	 * @return
	 */
	public boolean acquire() {
		//死循环,自旋,阻塞后重新获取锁
		for(;;) {
			System.out.println(Thread.currentThread().getName() + "cas操作");
			if (compareAndSet(0, 1)) {
				//获取锁成功
				getLockThread = Thread.currentThread();
				return true;
			} else {
				//获取锁失败
				Thread thread = Thread.currentThread();
				//将线程装入链表
				concurrentLinkedDeque.add(thread);
				//阻塞当前线程
				LockSupport.park();
				
				//经测试,阻塞后,不会打印和return
				//阻塞后,会停在park()这里,唤醒后,继续往下执行
				System.out.println(thread.getName() + "被唤醒");
			}
		}
	}
	
	/**
	 * 释放
	 * @return
	 */
	public boolean release() {
		if (getLockThread == null) {
			return false;
		} 
		
		if (getLockThread == Thread.currentThread()) {
			boolean result = compareAndSet(1, 0);
			if (result) {
				if (fairFlag == true) {
					//公平锁的唤醒,唤醒队列的第一个线程
					Thread thread = concurrentLinkedDeque.poll();
					LockSupport.unpark(thread);
				} else {
					//非公平锁的唤醒,循环释放队列里的所有线程
					while(true) {
						Thread thread = concurrentLinkedDeque.poll();
						if (thread != null) {
							LockSupport.unpark(thread);
						} else {
							break;
						}
					}
				}
				return true;
			}
			return false;
		}
		
		return false;
	}
	
	/**
	 * 实现CAS功能
	 * @param expect
	 * @param update
	 * @return
	 */
	public boolean compareAndSet(int expect, int update) {
		return lockState.compareAndSet(expect, update);
	}
	
	public static void main(String[] args) throws Exception {
		AqsTryLock aqsTryLock = new AqsTryLock(false);
		aqsTryLock.lock();
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName() + "start");
				aqsTryLock.lock();
				System.out.println(Thread.currentThread().getName() + "end");
			}
		}).start();
		
		Thread.sleep(1000);
		aqsTryLock.unlock();
	}
}

2、执行结果

maincas操作
Thread-0start
Thread-0cas操作
Thread-0被唤醒
Thread-0cas操作
Thread-0end

注:最新代码上传至https://github.com/csj50/webapp2.git
 

猜你喜欢

转载自blog.csdn.net/csj50/article/details/118558787
今日推荐