除了synchroinzed之外,JDK5之后还提供了更高级的锁 Lock。
实际上,Lock是一个interface,而实际上开发人员需要面对的,通常只有ReentrantLock和ReentrantReadWriteLock,下面就围绕这两个类进行讲解。
Lock(/lɑːk/) 接口的主要方法1. void lock(): 执行此方法时, 如果锁处于空闲状态, 当前线程将获取到锁. 相反, 如果锁已经
被其他线程持有, 将禁用当前线程, 直到当前线程获取到锁.
2. boolean tryLock():如果锁可用, 则获取锁, 并立即返回 true, 否则返回 false. 该方法和
lock()的区别在于, tryLock()只是"试图"获取锁, 如果锁不可用, 不会导致当前线程被禁用,
当前线程仍然继续往下执行代码. 而 lock()方法则是一定要获取到锁, 如果锁不可用, 就一
直等待, 在未获得锁之前,当前线程并不继续向下执行.
3. void unlock():执行此方法时, 当前线程将释放持有的锁. 锁只能由持有者释放, 如果线程
并不持有锁, 却执行该方法, 可能导致异常的发生.
4. Condition newCondition():条件对象,获取等待通知组件。该组件和当前的锁绑定,
当前线程只有获取了锁,才能调用该组件的 await()方法,而调用后,当前线程将缩放锁。
5. getHoldCount() :查询当前线程保持此锁的次数,也就是执行此线程执行 lock 方法的次
数。
6. getQueueLength():返回正等待获取此锁的线程估计数,比如启动 10 个线程,1 个
线程获得锁,此时返回的是 9
7. getWaitQueueLength:(Condition condition)返回等待与此锁相关的给定条件的线
程估计数。比如 10 个线程,用同一个 condition 对象,并且此时这 10 个线程都执行了
condition 对象的 await 方法,那么此时执行此方法返回 10
8. hasWaiters(Condition condition):查询是否有线程等待与此锁有关的给定条件
(condition),对于指定 contidion 对象,有多少线程执行了 condition.await 方法
9. hasQueuedThread(Thread thread):查询给定线程是否等待获取此锁
10. hasQueuedThreads():是否有线程等待此锁
11. isFair():该锁是否公平锁
12. isHeldByCurrentThread(): 当前线程是否保持锁锁定,线程的执行 lock 方法的前后分
别是 false 和 true
13. isLock():此锁是否有任意线程占用
14. lockInterruptibly():如果当前线程未被中断,获取锁
15. tryLock():尝试获得锁,仅在调用时锁未被线程占用,获得锁
16. tryLock(long timeout TimeUnit unit):如果锁在给定等待时间内没有被另一个线程保持,
则获取该锁。
注:从Lock中提供的基本API可以看到,它只负责获取锁和释放锁。如果需要实现类似wait()/notify()这种等待/通知的机制,还需要借助Condition接口。
Condition:Condition接口提供了最基本的实现等待/通知机制的API 这里先介绍一些它最基本的API。
- await():让当前线程进入WAITING状态,同时释放锁,
- signal():通知某个处于WAITING状态的线程,可以继续获取锁执行。
- signalAll():通知所有处于WAITING状态的线程,开始争抢锁然后执行。
public class MyService {
private Lock lock = new ReentrantLock();
//Lock lock=new ReentrantLock(true);//公平锁
//Lock lock=new ReentrantLock(false);//非公平锁
private Condition condition=lock.newCondition();//创建 Condition
public void testMethod() {
try {
lock.lock();//lock 加锁
//1:wait 方法等待:
//System.out.println("开始 wait");
condition.await();
//通过创建 Condition 对象来使线程 wait,必须先执行 lock.lock 方法获得锁
//:2:signal 方法唤醒
condition.signal();//condition 对象的 signal 方法可以唤醒 wait 线程
for (int i = 0; i < 5; i++) {
System.out.println("ThreadName=" + Thread.currentThread().getName()+ (" " + (i + 1)));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally
{
lock.unlock();
}
} }
ReentrantReadWriteLock:
class Cache {
private Map map = new ConcurrentHashMap<>();
private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void put(String key, Object value){
readWriteLock.writeLock().lock();
try {
System.out.println(key+"====正在签字: "+ value);
//耗时操作
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace(); }
map.put(key, value);
System.out.println("===签字完成===");
} finally {
readWriteLock.writeLock().unlock();
}
}
public Object get(String key){
Object result = null;
readWriteLock.readLock().lock();
try {
System.out.println(key + "====正在看大家的签字:");
//耗时操作
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {e.printStackTrace(); }
result = map.get(key);
System.out.println(key+"===看完了===");
} finally {
readWriteLock.readLock().unlock();
}
return result;
}
}
public class ReadWriteLockDemo {
public static void main(String[] args) {
Cache cache = new Cache();
//写
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
cache.put("线程名"+temp, "数据"+temp);
}, String.valueOf(i)).start();
}
//读
for (int i = 1; i <= 5; i++) {
final int temp = i;
new Thread(()->{
cache.get("线程名"+temp);
}, String.valueOf(i)).start();
}
}
}



