Lock接口历史
java1.5版本之前只有synchronized一种锁,lock是java1.5版本之后提供的接口。lock接口与synchronized接口功能相同,但是需要手动获取锁和释放锁。既然提供了lock锁那必然就有一定的优点,例如:
lock锁具有锁的可操作性,可以中断获取和超时获取锁等多种同步获取锁的优点。除此之外,lock锁还有一个非常强大的实现类重入锁和读写锁。
Lock接口的使用
Lock lock = new ReentrantLock(); lock.lock(); try{ //可能会出现线程安全的操作 }finally{ //一定在finally中释放锁 //也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常 lock.ublock(); }
lock接口和synchronized关键字的接口的区别
lock可以尝试非阻塞的获取锁,如果这一时刻没有被其他线程获取到,则成功获取。
Lock接口能被中断的获取锁,获取到锁的线程能够相应中断,当获取到锁的线程被中断时,中断异常将被抛出,并释放锁。
Lock接口可以在指定时间内获取锁,如果在有效时间内未获取到锁则返回。
Lock接口中长用的方法
void lock() //获取锁
void unlock() //释放锁
boolean trylock() //尝试获取锁,如果获取失败返回false
boolean trylcok(long time,TimeUtil util) //在指定时间内获取锁,若获取失败则返回false
void lockInterruptibly() //如果当前线程未被中断则获取锁。该方法也是获取锁,与lock()不同的是,该方法在获取过程中可以被中断
Lock中的重入锁ReetrantLock实现类
顾名思义,重入锁就是在一条线程获取到锁之后再次获取锁,就是所谓的重入锁。讲道理synchronized也同样可以做到,不同的是该实现类有个很重到的特性,就是可以实现公平与非公平获取。
公平获取就是线程等待时间越长的越先获取到锁,反之就是非公平获取。事实上,非公平获取要比公平获取的效率要高。
当然该锁是排他锁,也就是说在一个线程获取锁后,其他线程进入等待列队。即同一时刻有且只能有一个线程执行。
Lock锁中的读写锁ReetrantReadWriteLock
与重入锁有所不同的是,读写锁在同一时刻可以有多个线程同时访问。但在写线程访问时,其他读锁和写锁都将被阻塞,进入等待列队。读写锁维护了一对儿锁,一个读锁和一个写锁。通过读写锁分离,使得程序执行效率比一般的排他锁更高。(并发性:在资料上看到的是并发性更高,在这里我觉得效率更容易理解一丢丢)
读锁:readlock();
写锁:writelock();
public class Cache{ static Map<String,Object> map = new HashMap<String,Object>(); static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); static Lock rLock = rwl.readLock(); static Lock wLock = rwl.writeLock(); //获取一个key对应的value public static final Object get(String key){ r.lock(); try{ return map.get(key); }finally{ r.unlock(); } } //设置key对应的value并返回旧的value public static fianl Object put(String key,Object value){ w.lock(); try{ return map.put(key,value); }final{ w.unlock(); } } //清空缓存 public static fianl void clear(){ w.lock(); try{ map.clear(); } finally{ w.unlock(); } } }
读写锁的锁降级
锁降级是指写锁降级成为读锁。如果当前线程持有写锁,然后将其释放再获取读锁的过程不能称为锁降级。锁降级指的在持有写锁的时候再获取读锁,获取到读锁后释放之前写锁的过程称为锁释放。
锁降级在某些情况下是非常必要的,主要是为了保证数据的可见性。如果当前线程不获取读锁而直接释放写锁,假设此时另外一个线程获取了写锁并修改了数据。那么当前线程无法感知该线程的数据更新。
(没怎么看明白,用程序走几次就明白了。实践见真理)。