【JUC】3.ReentrantLock
ReentrantLock实现Lock接口,所以先看下Lock接口: public interface Lock { // 获得锁
void lock(); // 获得锁
void unlock(); // lock非阻塞版本,成功返回true
boolean tryLock(); // 添加尝试时间,时间到返回false
boolean tryLock(long time,TimeUnit unit) // 返回一个监视器对象
Condition newCondition(); }
再来看ReentrantLock的常用API:? public class ReentrantLock implements Lock,Serializable { // 构造器,可以实现公平锁
public ReentrantLock() public ReentrantLock(boolean fair) public void lock() // 可中断锁
public void lockInterruptibly() // 可轮询的锁获取,有返回值。获取成功返回true;获取失败,返回false,线程不会阻塞、
public boolean tryLock() public boolean tryLock(long timeout,TimeUnit unit) // 返回一个监视器对象
Condition newCondition(); }?
ReentrantLock的使用方法分为这么几块: 1. 可重入锁的实现; 2. 公平锁与非公平锁; 3. 配合Condition实现的选择性通知,?condition实现阻塞队列,这两个可以视为同一块; 4.?tryLock的实现; 5.生产者消费者模式实现,如果用Condition实现这个模式,其实跟实现阻塞队列是类似的; ? ?同样也可以单纯使用阻塞队列实现生产者消费者模式; 可重入锁的实现可以再次获取自己的内部锁,即:一个线程获取某对象锁,在没有释放此对象锁的同时,可以再次获得此锁; 锁释放请务必在finally中进行 public class ReentrantLockTest { private static final Lock lock = new ReentrantLock(); public static void test1() { lock.lock(); try { System.out.println("已进入test_1"); test2(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void test2() { lock.lock(); try { System.out.println("已进入test_2"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
公平锁与非公平锁只要在构造器中传入true,实现方面没什么好说的;
?非公平锁虽然效率高,但是有可能出现线程饿死的情况,比如客户端一直无法获得服务,所以,服务器一般用公平锁实现; 这个可以跟实现阻塞队列一起说了,感觉代码层面,基本一致; ? public class MyBlockingQueue<T> { private int limit; private final Lock lock = new ReentrantLock(); private final Condition Full = lock.newCondition(); private final Condition Empty = lock.newCondition(); private List<T> queue = new LinkedList<>(); public MyBlockingQueue(int limit) { this.limit = limit; } public void enqueue(T item) throws InterruptedException { lock.lock(); try { // 队列满 while (queue.size() == limit) { Full.await(); } queue.add(item); Empty.signal(); } finally { lock.unlock(); } } public T dequeue(T item) throws InterruptedException { lock.lock(); try { // 队列空 while (queue.size() == 0) { Empty.await();// 将当前线程阻塞在Empty监视器下 } Full.signal(); // 叫醒Full监视器下阻塞的线程 return queue.remove(0); } finally { lock.unlock(); } } } tryLock的实现tryLock方法可以无参,可以传入等待时间; public class MytryLock { private static final Lock lock = new ReentrantLock(); // 由于是否获得锁不确定,所以设置标志位判断 private static boolean isLocked = false; public static void test() { try { if (lock.tryLock(1000,TimeUnit.MILLISECONDS)) { // trylock返回true,即拿到锁 isLocked = true; System.out.println(Thread.currentThread().getName() + "拿到锁!"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } else { /** * 没拿到锁,可以让线程继续做别的事 * 不会阻塞 */ System.out.println(Thread.currentThread().getName() + "没拿到锁!"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (isLocked == true) lock.unlock(); } } } 生产者消费者模式实现同condition实现阻塞队列; queue就是生产者的仓库对象; enqueue就是生产; dequeue就是消费; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |