代码中有详细注释,这里不做说明了,解释一下涉及到的名词:
AQS:AbstractQueuedSynchronizer。是所有并发工具实现的框架基础。
可重入锁:自己可以重新获取自己当前获取的锁(比较绕口),不可重入的话自身会把自身锁死!
非公平锁:后来的线程可能先拿到锁,即拿到所的顺序是不公平的(这样反而性能更好)
互斥锁:只有一个线程能拿到锁,其他线程会被阻塞。
实现代码如下:
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; public class ExclusiveLock implements Lock { // 生成同步器私有变量 private final Sync sync = new Sync(); // 静态内部类,同步器!继承AQS,是实现锁的核心 private class Sync extends AbstractQueuedSynchronizer{ @Override protected boolean tryAcquire(int acquire) { if (compareAndSetState(0,acquire)){ // CAS *** 作设置锁的状态, // 成功代表拿到锁,将当前线程设置为持有锁的线程 setExclusiveOwnerThread(Thread.currentThread()); return true; // 拿到了锁 }else if (getExclusiveOwnerThread() == Thread.currentThread()){ // 重入,判断拿到锁的是不是当前线程 // 是,意味重入,锁的层级+acquire ; // 先判断 锁的状态是否 > 0,确保正常!否则提示超出锁计数。 if (getState() + acquire < 0){ throw new Error("Maximum lock count exceeded!"); } // 这里不用CAS是因为是单线程执行的(锁被单一线程持有),一定不会出现并发安全性问题 setState(getState() + acquire); return true; } // 其余都是未拿到锁,尝试拿到锁失败。 return false; } @Override protected boolean tryRelease(int acquire) { if (getExclusiveOwnerThread() != Thread.currentThread()){ // 抛出该异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器,然而本身没有指定的监视器的线程。 // 简单的说就是当前线程不是 对象监控器 的所有者 throw new IllegalMonitorStateException(); }else if (getState() == 0){ throw new IllegalMonitorStateException(); } // 检查通过,锁的层级-- 不使用CAS操作原因同上 setState(getState() - acquire); if (getState() == 0){ // 锁的层级为0,代表失去锁的持有,将锁的持有线程设置为空 setExclusiveOwnerThread(null); // 已经没有线程对锁持有,返回释放成功! return true; } // 正常执行到这里代表当前线程还持有对锁的持有,因此释放锁失败! return false; } //方法名直译:是否独占?(不用说了吧!) @Override protected boolean isHeldExclusively() { // 根据getState() 判断锁的状态 return getState() > 0; } Condition newCondition(){ return new ConditionObject(); } } @Override public void lock() { // System.out.println(提示1); sync.acquire(1); // System.out.println(提示2);或者写自己的逻辑....... } @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(); } }
测试:
public class LockTest{ // 号令q,确保同时争抢锁,之前文档有做说明 private CountDownLatch countDownLatch = new CountDownLatch(1); private int count = 0; private final ExclusiveLock lock = new ExclusiveLock(); private class Test extends Thread{ @Override public void run() { try { countDownLatch.await(); lock.lock(); Thread.sleep(1000); System.out.println(Thread.currentThread().getName()); if (count < 3){ ++count; System.out.println(System.currentTimeMillis()+"===="+count+"==="+Thread.currentThread().getName()); } lock.unlock(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { LockTest lockTest = new LockTest(); for (int i=0;i<10;i++){ Test tt = lockTest.new Test(); tt.start(); } lockTest.countDownLatch.countDown(); } }
间隔一秒,说明资源被锁定了一段时间。
公平锁在实际中较少使用:
实现只需要把上面那个tryAcquire()中的逻辑稍微修改即可。
@Override protected boolean tryAcquire(int acquire) { // 判断是否还有前驱节点,直接自己为头节点了或者同步队列空了才会继续后面的锁的获取 *** 作 if (!hasQueuedPredecessors() && compareAndSetState(0,acquire)){ setExclusiveOwnerThread(Thread.currentThread()); return true; }else if (getExclusiveOwnerThread() == Thread.currentThread()){ if (getState() + acquire < 0){ throw new Error("Maximum lock count exceeded!"); } setState(getState() + acquire); return true; } return false; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)