欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

锁-独占锁、同步队列器

程序员文章站 2022-06-28 17:17:45
Lock接口锁是用来控制多个线程访问共享资源的方式。一个锁可以防止多个线程同时访问共享资源(读写锁,允许多个线程并发的访问共享资源) public static void main(String[] args) { Lock lock = new ReentrantLock(); lock.lock(); try { } finally { lock.unlock(); } }这是锁的...

Lock接口
锁是用来控制多个线程访问共享资源的方式。一个锁可以防止多个线程同时访问共享资源(读写锁,允许多个线程并发的访问共享资源)

 public static void main(String[] args) {
        Lock lock = new ReentrantLock();

        lock.lock();
        try {

        } finally {
            lock.unlock();
        }
    }

这是锁的基本使用方式。
在finally块中释放锁,目的就是在获取锁后,能够最终释放锁。
不要将获取锁的过程写在try里面。如果获取锁发生异常抛出的时候,会导致锁无故释放。

队列同步器

AbstractQueuedSynchronizer(同步器),是用来构建锁或者其他同步组件的基础框架。
同步器的主要使用方式是继承子类通过继承同步器并实现他的抽象方法,通过内置的FIFO队列来完成资源获取线程的排队工作。
同步器支持独占式的获取同步状态,也可以共享式的获取同步状态。
同步器的设计是基于模板方法模式的,也就是说,使用者必须继承同步器并重写指定的方法,随后将同步器组合在自定义同步组件的实现中,并调用同步器提供的模板方法,这些模板方法会调用使用者重写的方法。
重写同步器指定的方法时,需要使用这三个方法访问或者修改同步状态
getSate():获取当前同步状态
setState():设置当前同步状态
compareAndSetState(int expect,int update): 使用CAS设置当前状态,该方法能够保证状态设置的原子性


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;

public class Mutex {
    //静态内部类
    private static class Sync extends AbstractQueuedSynchronizer {
        //是否处于占用状态
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        //当状态为1时,获取锁
        @Override
        protected boolean tryAcquire(int acquires) {
            if (compareAndSetState(0, 1)) {

                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        //释放锁,将状态设置为0
        @Override
        protected boolean tryRelease(int release) {
            if (getState() == 0) {
                throw new IllegalArgumentException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        //返回一个condition,每个condition都包含一个condition队列
        Condition newCondition() {
            return new ConditionObject();
        }
    }

//仅需要把操作代理到sync即可
    private final Sync sync = new Sync();

    public void lock() {
        sync.acquire(1);
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    public void unlock() {
        sync.release(1);
    }

    public Condition newCondition() {
        return sync.newCondition();
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueueThreads() {
        return sync.hasQueuedThreads();
    }

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }
}

上面可以看出:独占锁Mutex是一个自定义同步组件,他在同一时刻只允许一个线程占有锁。
在tryAcruire(int acruires)中,如果经过CAS设置成功(状态设置为1),则代表获取了通报状态。而在tryRelease(int release)中只是将同步状态重置为0.
同步器可以重写的方法

方法名称 描述
protect boolean tryAcruire(int arg) 独占式获取锁。实现前需要查询当前状态,并判断是否符合预期,然后经过CAS设置同步状态
protect boolean tryRelease(int arg) 独占式释放锁。等待获取锁的线程将有机会获取锁
protect boolean tryAcruireShared(int arg) 共享式获取锁,返回大于等于0的值,获取成功。反之,获取失败
protect boolean tryReleaseShared(int arg) 共享式释放锁
protect boolean isHeldExclusively() 查询当前线程是否被独占

同步器提供的模板方法??有疑问

void acquire(int arg) 独占式获取锁,如果获取成功就返回,如果失败,将会进入同步队列中等待。该方法会调用重写的tryAcquire方法
void acquireInterruptibly(int arg) 与上面不同的是,这个可以响应中断,当前线程为获取到锁而进入到同步队列中,如果该线程被中断,或抛出异常
boolean tryAcquireNanos(int arg,long nanos) 在void acquireInterruptibly(int arg)基础上加了超时限制。时间内获取成功就返回true,否则,返回false
void acquireShared(int arg) 共享式获取同步状态,如果为获取到,进入同步队列。同一时刻可以有多个线程获取到同步状态
boolean release(int release) 独占式释放同步状态,释放后,会将同步队列的第一个节点包含的线程唤醒
boolean releaseShared(int release) 共享式释放同步状态
Collection getQueueThreads() 获取到同步队列上的线程集合

本文地址:https://blog.csdn.net/m0_50590769/article/details/109565526