在java多线程编程中,我们经常使用synchronized关键字来实现同步,控制多线程对变量的访问,来避免并发问题。
但是有的时候,synchronized关键字会显得过于沉重,不够灵活。
1、效率低:锁的释放情况少、试图获得锁时不能设定超时、不能中断一个正在试图获得锁的线程。
2、不够灵活(读写锁更灵活):加锁和释放的时机单一,每个锁仅有单一的条件(某个对象),可能是不够的。
3、无法知道是否成功获取到锁。
这个时候Lock接口出现。Lock不是java中的关键字而是一个java.util.concurrent.locks包中的一个接口。下面我们简单介绍一下Lock接口。
一 Lock接口简介
Lock实现提供了比使用synchroized方法和语句可以获得的更广泛的锁定操作,此实现允许更灵活的结构,还可以支持多个相关的Condition对象。
Lock lock=new ReentrantLock();
lock.lock();
try {
//业务代码
}finally {
lock.unlock();
}
锁的锁定和释放如果在不同的模块时,需要小心编码,确保最后锁一定能得到释放。
二 Lock接口中定义的方法
1 void lock()
获取锁,如果锁不可用,出于线程调用目的,将禁用当前线程,并且在获取锁之前,该线程一直处于休眠状态。
2 void lockInterruptibly() 如果当前线程未被中断,则获取锁。
3 Condition newCondition() 返回绑定到此Lock实例的新Condition实例。
4 boolean tryLock()仅在调用锁为空闲状态才获取锁,如果锁可用,则获取锁,并立即返回值为true,如果锁不可用,则此方法立即返回值为false。
5 boolean tryLock(long time,TimeUnit unit) 如果锁在给定的的等待时间内空闲,并且当前线程未被中断,则获取锁。
6 void lock() 释放锁,在等待条件前,锁必须由当前线程保持,
三 实现类 ReentrantLock
Lock接口有三个实现类ReentrantLock,ReentrantLockReadWirteLock.ReadLock,
ReentrantLockReadWirteLock.WriteLock。后面两个是内部类。
其中一个ReentrantLock,在我们平常中使用更为频繁。
是一个可重入的互斥锁Lock,它具有与使用synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
ReentrantLock的构造方法接受一个可选的公平参数,当设置为true时,在多个线程的竞争下,这些锁倾向于将访问权授予等待时间最长的线程,否则此锁将无法保证访问顺序,公平锁也只是趋向公平,并不能完全保证。
ReentrantLock类中还定义了Lock接口之外的方法,例如int getHoldCount(),boolean hasQueuedThreads(),boolean hasWaiters(Condition condition)等等,这些方法可以查询锁的状态。
下面我们用Lock简单实现下多线程的一个同步,新建5个线程一次打印奇偶数,实现了线程按照顺序来执行。先看运行结果。
主要代码如下:
网友评论