【JUC】3.ReentrantLock
ReentrantLock实2477203708现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,实现方面没什么好说的;
-
-
公平锁下后来的线程必须排队等待锁的释放,多进行了一步判断,线程挂起的几率比较高,所以效率略低
满足FIFO(先进先出队列)
非公平锁虽然效率高,但是有可能出现线程饿死的情况,比如客户端一直无法获得服务,所以,服务器一般用公平锁实现;
这个可以跟实现阻塞队列一起说了,感觉代码层面,基本一致;
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就是消费;