今天重新整理关于concurrent包的使用。
Lock 接口, 提供了synchronized的功能, 同时额外增加复杂性,处理复杂问题的能力,因为在synchronized的时候,可以顺序的获取多个锁,同时也需要倒序的释放这些锁,碰到一些情况这个就不能满足了,这时候Lock就可以,
它实现了锁在不同作用范围的获取和释放,同时不同顺序的获取和释放。
通常这样使用
Lock l = ...
l.lock();
try{
}finally{
l.unlock();
}
没有了synchronized的自动释放锁的能力,手动做
Lock 的一些功能
一个非块结构的获取锁, tryLock()
获取可中断锁的尝试, tryInterruptibly()
获取超时失效锁的尝试, tryLock(Long, timeUnit);
重这3个方法中,看出来有三种获取锁的方式,可中断,不可中断,定时
ReadWriteLock 接口, 提供了多个线程同时访问共享资源的能力,它由一对读-写锁组成,读锁可以被多个线程共享,写只能独占,并且保证了数据的内存同步,写的结果在读中,即时可得。
它适用于,需要经常被读,但是写的较少的情况,简单说,就是读的时间长的
ReentrantLock 实现了Lock 的 可重入互斥锁, 具有synchronized语句访问隐式锁的相同的基本语义和行为,但更强大。它提供了很多的方法来检查当前锁的情况,包括当前线程是否拥有锁,isHeldByCurrentThread(), 等待的线程, getWaitingThreads(Condition), getQueuedThreads(), getHoldCount(), getOwner(), hasXXX, 等方法来查看是否有等待线程,等待的数量等。
它还提供了一个fair参数,来实现公平策略,即当多个线程竞争的时候,倾向于等待时间最长的线程,当然是不保证的,并且可能很慢。同时使用tryLock()方法是不管公平的,只要锁空闲,就可获取。
Condition 接口,与每个Lock相关,newCondition()创建, 在我看来Condition就是Object中wait,notify的升级版,Object中使用的隐式锁机制的wait,notify需要保持一个锁, Condition不需要, 同时Condition 可以提供唤醒的通知顺序控制,可以对一个锁有多个Condition。
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
CountDownLatch
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
主要方法
public CountDownLatch(int count);
public void countDown();
public void await() throws InterruptedException
构造方法参数指定了计数的次数
countDown方法,当前线程调用此方法,则计数减一
awaint方法,调用此方法会一直阻塞当前线程,直到计时器的值为0