Java 并发包concurrent包下主要提供lock和ReadWrite两种接口,提供两种类型的锁。
1.ReentrantLock类
由于ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:
等待可中断
持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。公平锁
多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。锁绑定多个条件
一个ReentrantLock对象可以同时绑定对个对象,阻塞队列(BlockingQueue)就是基于lock的多条件实现的,可以查看Java并行编程-lock中使用多条件condition(生产者消费者模式实例)。
ReentrantLock(可重入锁)实现lock接口。常用的方法有lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用来获取锁的。unLock()方法
是用来释放锁的。
lock():尝试获取获取锁,如果成功立即返回,如果不成功进入休眠。
tryLock():尝试获取锁,不管成功与否,立即返回true/false(这也是lock比Synchronized更灵活)。
tryLock(long time, TimeUnit unit):与tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。
lockInterruptibly():方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态,所以lock是可中断的。
使用例如如下,一定要在finally中unlock(),避免发生异常时出现死锁.
public class SynDemo{
public static void main(String[] arg){
Runnable t1=new MyThread();
new Thread(t1,"t1").start();
new Thread(t1,"t2").start();
}
}
class MyThread implements Runnable {
private Lock lock=new ReentrantLock();
public void run() {
lock.lock();
try{
for(int i=0;i<5;i++)
System.out.println(Thread.currentThread().getName()+":"+i);
}finally{
lock.unlock();
}
}
}
2.ReentrantReaderWriteLock类。
ReentrantReaderWriteLock实现的是ReadWriteLock接口,用法与ReentrantLock相似。读写锁把锁分为读锁和写锁,能提高并发的效率,长用在读数据比较多,写数据比较少的场景。
readLock():获取读锁,不会造成阻塞。
writeLock():获得写锁,写的时候阻塞读线程和写线程。
如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。
如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。
对ReentrantLock的源码分析这有一篇很好的文章http://www.blogjava.net/zhanglongsr/articles/356782.html
对读写锁的使用场景: http://blog.csdn.net/it_man/article/details/8972001
关于锁的详细使用可以查看这篇文章:http://www.cnblogs.com/dolphin0520/p/3923167.html