Java Lock与Condition的理解 ReentrantLock锁的简单使用

1 篇文章 0 订阅

Lock

ReentrantLock 是我们常用的锁,日常我们都只使用了其中一部分功能如下:

        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        try {
            .... 
        } finally {
            lock.unlock();
        }

实际上Java提供的LinkedBlockingQueue类就是基于ReentrantLock与Condition结合使用的,这是很经典的生产与消费场景,里面有两个锁putLock与takeLock锁。解决问题:取元素时takeLock已经获取到锁了,但是由于列队是空的,使用notEmpty.await()使当前线程处理等待状态,这时如果有新的线程调用take方法时,新的线程也能获取到锁,也会继续等待,当put元素后, notEmpty.signal()发送信号,会唤醒其中一个等待线程。
使用condition可以使线程交互变的更加灵活,ReentrantLock可以定义公平锁与非公平锁,公平锁可以保证线程访问顺序,非公平锁不一定保证线程访问顺序,默认为非公平锁。

take方法

//每次取完之后使用自唤醒方法使其它等待线程,多了一重信息通知,取完之后会调用notFull方法唤醒正在等写入的方法
public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();//获取锁
        try {
            while (count.get() == 0) {//如果当前元素为0线程等待
                notEmpty.await();
            }
            x = dequeue();//取一个元素
            c = count.getAndDecrement();//总数减1
            if (c > 1)//如果有元素 继续唤醒一个等待线程
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }

put方法

public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    int c = -1;
    Node<E> node = new Node<E>(e);
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly();
    try { 
        while (count.get() == capacity) {//列队满,等列队有空间
            notFull.await();
        }
        enqueue(node);//插入元素
        c = count.getAndIncrement();//总数加1
        if (c + 1 < capacity)//列队未满,唤醒正在等待的线程
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    if (c == 0)//通知正在等待取元素的线程
        signalNotEmpty();
}

synchronized锁

synchronized (writeLock) {
    while (runThreadNum >= 5) {
        try {
            System.out.println("threadNum:" + runThreadNum);
            writeLock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试代码实例


import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by zengrenyuan on 18/6/11.
 */
public class TestLock {

    public static final int maxNum = 1;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        final TestLock testLock = new TestLock();
        testLock.putThread("线程1");
        testLock.putThread("线程2");
        testLock.putThread("线程3");
        testLock.putThread("线程4");
        testLock.putThread("线程5");
        testLock.readThread("读线程");
    }

    public void readThread(String name) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        read();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread.setName(name);
        thread.start();


    }

    public void read() throws InterruptedException {
        lock.lock();
        try {
            while (count.get() == 0) {
                notEmpty.await();
            }
            System.out.println("read:" + count.decrementAndGet());
            notFull.signal();
        } finally {
            lock.unlock();
        }
    }


    public void putThread(String name) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    print();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.setName(name);
        thread.start();
    }

    public void print() throws InterruptedException {
        lock.lock();
        try {
            System.out.println("threadName" + Thread.currentThread().getName());
            while (count.get() == maxNum) {
                notFull.await();
            }
            System.out.println("put:" + count.getAndIncrement() + " threadName" + Thread.currentThread().getName());
            System.out.println(MiscUtils.formatDate(new Date(), MiscUtils.STANDARDPATTERN));
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }


}

参考文章

https://www.jianshu.com/p/eb112b25b848
http://jszx-jxpt.cuit.edu.cn/JavaAPI/java/util/concurrent/locks/Condition.html
http://jszx-jxpt.cuit.edu.cn/JavaAPI/java/util/concurrent/locks/Lock.html
https://www.jianshu.com/p/71ad3c675cbe

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值