Java提高——JUC锁02-互斥锁ReentrantLock

ReentrantLocak

ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”。

ReentrantLock锁在同一个时间点只能被一个线程持有;而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取

ReentrantLock分为“公平锁”和“非公平锁”。他们最大的区别体现在获取锁的机制上是否公平。“锁”是为了保护竞争资源,防止多个线程同时操作线程而出错,ReentrantLock在同一个时间点只能被一个线程获取(当某线程获取到“锁”时,其他线程就必须等待);ReentrantLock是通过一个FIFO的等待队列来管理获取该锁的所有线程的。在“公平锁”的机制下,线程一次排队获取;而“非公平锁”在锁是可获取状态的时候,不管自己是不是在队列开头都会获取锁。

ReentrantLock的函数列表

/**
 * 创建一个ReentrantLock,默认是“非公平锁”
 */
public ReentrantLock() {
    sync = new NonfairSync();
}

/**
 * 创建策略是faire的ReentrantLock。fair为true表示是公平锁,为false表示为非公平锁
 */
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

/**
 * 获取锁
 */
public void lock() {
    sync.lock();
}

/**
 * 如果当前线程未被中断则获取锁
 */
public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}

/**
 * 仅在调用时,锁未被另一个线程保持的状况下才获取锁
 */
public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}

/**
 * 如果锁在给定的时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁
 */
public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

/**
 * 视图释放此锁
 */
public void unlock() {
    sync.release(1);
}

/**
 * 返回与此Lock实例一起使用的Condition实例
 */
public Condition newCondition() {
    return sync.newCondition();
}

/**
 * 查询当前线程保持此锁的次数
 */
public int getHoldCount() {
    return sync.getHoldCount();
}

/**
 * 该锁是否被当前线程保持
 */
public boolean isHeldByCurrentThread() {
    return sync.isHeldExclusively();
}

/**
 * 查询此锁是否由任意线程保持
 */
public boolean isLocked() {
    return sync.isLocked();
}

/**
 * 判断是否是公平锁
 */
public final boolean isFair() {
    return sync instanceof FairSync;
}

/**
 * 返回目前拥有此锁的线程
 */
protected Thread getOwner() {
    return sync.getOwner();
}

/**
 * 查询是否有些线程正在等待获取此锁
 */
public final boolean hasQueuedThreads() {
    return sync.hasQueuedThreads();
}

/**
 * 查询给定线程是否正在等待获取此锁
 */
public final boolean hasQueuedThread(Thread thread) {
    return sync.isQueued(thread);
}

/**
 * 返回正在等待获取此锁的线程估计数
 */
public final int getQueueLength() {
    return sync.getQueueLength();
}

/**
 * 返回包含可能正在等待的线程的集合
 *
 * @return the collection of threads
 */
protected Collection<Thread> getQueuedThreads() {
    return sync.getQueuedThreads();
}

/**
 * 查询是否有线程正在等待
 */
public boolean hasWaiters(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}

/**
 * 返回等待与此锁相关的给定条件的线程估计数
 */
public int getWaitQueueLength(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}

实例:认识lock和unlock

第一版:

class Depot{
    private Integer size;//仓库的实际数量
    private Lock lock;//独占锁

    public Depot() {
        this.size = 0;
        this.lock = new ReentrantLock();
    }

    public void produce(int val){
        lock.lock();//加锁
        try {
            size += val;
            System.out.println(Thread.currentThread().getName()+","+val +","+size);
        } finally {
            lock.unlock();//释放锁
        }
    }

    public void consume(int val){
        lock.lock();
        try {
            size -= val;
            System.out.println(Thread.currentThread().getName()+","+val +","+size);
        } finally {
            lock.unlock();
        }
    }
}
class producer{
    private Depot depot;

    public producer(Depot depot) {
        this.depot = depot;
    }

    //新建一个线程向仓库中生产产品
    public void produce(int val){
        new Thread(){
            @Override
            public void run(){
                depot.produce(val);
            }
        }.start();
    }
}
class cunsumer{
    private Depot depot;

    public cunsumer(Depot depot) {
        this.depot = depot;
    }
    //新建一个线程向仓库中生产产品
    public void consume(final int val){
        new Thread(){
            @Override
            public void run(){
                depot.consume(val);
            }
        }.start();
    }
}

public class TestLock {
    public static void main(String[] args) {
        Depot depot = new Depot();
        producer p = new producer(depot);
        cunsumer c = new cunsumer(depot);

        p.produce(60);
        p.produce(120);
        c.consume(90);
        c.consume(150);
        p.produce(110);
    }
}


1)Depot仓库通过produce向其中生产货物,通过consume消耗仓库中的货物。通过独占锁lock实现仓库的互斥访问:在操作仓库中的货物前会通过lock锁住仓库,操作完成之后通过unlock解锁。

2)producer通过调用produce方法新建一个线程向仓库中生产货物

3)consumer通过consume方法通过新建一个线程消耗仓库中的货物

4)主线程main中建一个消费者和生产者,分别用于生产和消耗。最终剩余50.

该模型中会有仓库为负和容量无限制的问题

第二版:解决上面两个问题,通过Condition来解决,通过Condition的await( )方法,让线程阻塞(类似于wait());通过signal( )方法让线程唤醒(类似于notify())。

class Depot{
    private Integer capacity;//仓库的容量
    private Integer size;//仓库的实际数量
    private Lock lock;//独占锁
    private Condition fullCondition;//生产条件
    private Condition emptyCondition;//消耗的条件

    public Depot(Integer capacity) {
        this.capacity = capacity;
        this.size = 0;
        this.lock = new ReentrantLock();
        this.fullCondition = lock.newCondition();
        this.emptyCondition = lock.newCondition();
    }

    public void produce(int val){
        lock.lock();//加锁
        try {
            //wantProduceVal表示想要生产的数量(可能量太多需要多次生产)
            int wantProduceVal=val;

            while (wantProduceVal>0){
                //实际数量大于等于容量,库满,等待
                while (size>=capacity){
                    fullCondition.await();
                }
                    //获取实际生产的量,(即库存中新增的量)
                    //如果 库存+想要生产的量>库容量,则 实际的增量=库容量-库存,
                    //否则,实际增量=想要生产的量
                    int inc = (size+wantProduceVal)>capacity?(capacity-size):wantProduceVal;
                    size+=inc;
                    wantProduceVal-=inc;
                    //size += val;
                    System.out.println(Thread.currentThread().getName()+","+val +","+size);

                    //通知消费者消费
                    emptyCondition.signal();
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//释放锁
        }
    }

    public void consume(int val){
        lock.lock();
        try {
            //表示想要消耗的量(可能量太大)
            int wantConsumeVal = val;
            //没有库存则等待生产
            while (size<0) {
                emptyCondition.await();
            }
                //获取实际消耗的量(即库存中实际减少的量)
                //如果 存库<要消耗的量,那么消耗量等于库存
                //否则,减少的量就是要消耗的量
                int dec = (wantConsumeVal>size)?size:wantConsumeVal;
                size-=dec;
                wantConsumeVal-=dec;
                //size -= val;
                System.out.println(Thread.currentThread().getName()+","+val +","+size);

                //通知生产者生产
                fullCondition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
class producer{
    private Depot depot;

    public producer(Depot depot) {
        this.depot = depot;
    }

    //新建一个线程向仓库中生产产品
    public void produce(int val){
        new Thread(){
            @Override
            public void run(){
                depot.produce(val);
            }
        }.start();
    }
}
class cunsumer{
    private Depot depot;

    public cunsumer(Depot depot) {
        this.depot = depot;
    }
    //新建一个线程向仓库中生产产品
    public void consume(final int val){
        new Thread(){
            @Override
            public void run(){
                depot.consume(val);
            }
        }.start();
    }
}

public class TestLock {
    public static void main(String[] args) {
        Depot depot = new Depot(100);
        producer p = new producer(depot);
        cunsumer c = new cunsumer(depot);

        p.produce(60);
        p.produce(120);
        c.consume(90);
        c.consume(150);
        p.produce(110);
    }
}


转载请注明出处:http://www.cnblogs.com/skywang12345/p/3496147.html

原文地址:https://www.cnblogs.com/huangzhe1515023110/p/9276045.html