• Lock 显示锁


    锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但是有些锁可以允许多个线程并发的访问共享资源,比如读写锁)。

    在Lock接口出现之前,Java程序是靠synchronized关键字实现锁功能的,而Java SE 5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。

    虽然它缺少了(通过synchronized块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。

    Java并发包中的显式锁接口和类位于包java.util.concurrent.locks下,主要接口和类有:

    ❑ 锁接口Lock,主要实现类是ReentrantLock;

    ❑ 读写锁接口ReadWriteLock,主要实现类是ReentrantReadWriteLock。

    Lock接口

    显式锁接口Lock的定义为:

    public interface Lock {
        void lock();
        void lockInterruptibly() throws InterruptedException;
        boolean tryLock();
        boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
        void unlock();
        Condition newCondition();
    }
    

    1)lock()/unlock():就是普通的获取锁和释放锁方法,lock()会阻塞直到成功。

    2)lockInterruptibly():与lock()的不同是,它可以响应中断,如果被其他线程中断了,则抛出InterruptedException。

    3)tryLock():只是尝试获取锁,立即返回,不阻塞,如果获取成功,返回true,否则返回false。

    4)tryLock(long time, TimeUnit unit):先尝试获取锁,如果能成功则立即返回true,否则阻塞等待,但等待的最长时间由指定的参数设置,在等待的同时响应中断,如果发生了中断,抛出InterruptedException,如果在等待的时间内获得了锁,返回true,否则返回false。

    5)newCondition:新建一个条件,一个Lock可以关联多个条件。

    可以看出,相比synchronized,显式锁支持以非阻塞方式获取锁、可以响应中断、可以限时,这使得它灵活得多。

    重入锁ReentrantLock

    Lock接口的主要实现类是ReentrantLock,它的基本用法lock/unlock实现了与syn-chronized一样的语义,包括:

    ❑ 可重入,一个线程在持有一个锁的前提下,可以继续获得该锁;

    ❑ 可以解决竞态条件问题;

    ❑ 可以保证内存可见性。

    ReentrantLock有两个构造方法:

    public ReentrantLock()
    public ReentrantLock(boolean fair)
    

    参数fair表示是否保证公平,不指定的情况下,默认为false,表示不保证公平。所谓公平是指,等待时间最长的线程优先获得锁。保证公平会影响性能,一般也不需要,所以默认不保证,synchronized锁也是不保证公平的

    使用显式锁,一定要记得调用unlock。一般而言,应该将lock之后的代码包装到try语句内,在finally语句内释放锁。比如,使用ReentrantLock实现Counter,代码可以为:

    public class Counter {
        private final Lock lock = new ReentrantLock();
        private volatile int count;
        public void incr() {
            lock.lock();
            try {
                count++;
            } finally {
                lock.unlock();
            }
        }
        public int getCount() {
            return count;
        }
    }
    

    读写锁ReentrantReadWriteLock

    ReadWriteLock仅定义了获取读锁和写锁的两个方法,即readLock()方法和writeLock()方法

    ReentrantReadWriteLock使用方式如下:

    public class Cache {
        private static final Map<String, Object>    map = new HashMap<String, Object>();
        private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
        private static final Lock                   r   = rwl.readLock();
        private static final Lock                   w   = rwl.writeLock();
        public static final Object get(String key) {
            r.lock();
            try {
                return map.get(key);
            } finally {
                r.unlock();
            }
        }
        public static final Object put(String key, Object value) {
            w.lock();
            try {
                return map.put(key, value);
            } finally {
                w.unlock();
            }
        }
        public static final void clear() {
            w.lock();
            try {
                map.clear();
            } finally {
                w.unlock();
            }
        }
    }
    

    也就是说,当使用 ReadWriteLock 的时候,并不是直接使用,而是获得其内部的读锁和写锁,然后分别调用lock/unlock。

    从表面来看,ReadLock和WriteLock是两把锁,实际上它只是同一 把锁的两个视图而已。什么叫两个视图呢?可以理解为是一把锁,线程分成两类:读线程和写线程。读线程和读线程之间不互斥(可以同时拿到这把锁),读线程和写线程互斥,写线程和写线程也互斥。

    参考: Java编程的逻辑 16.2 显式锁

      Java并发编程的艺术 5.1 Lock接口

      Java并发实现原理 3.1 互斥锁

  • 相关阅读:
    深入分析java的clone
    java实现文件夹遍历
    插入排序的C语言实现
    java动态代理工厂类
    HTML 理解标签 帧
    贝塞尔曲线初探
    警告:未初始化的变量引起运行问题
    解释string类型的输入操作符和getline函数分别如何处理空白符
    程序书写规范笔记
    vector
  • 原文地址:https://www.cnblogs.com/ooo0/p/15843225.html
Copyright © 2020-2023  润新知