java.util.concurrent.locks.Lock
Lock接口与synchronized的区别:
1.Lock接口允许分离读和写操作,允许多个读线程和只有一个写线程
2.在高并发的环境下,Lock性能更好
3.支持更灵活的同步代码块结构,可以让锁的获取和释放不在同一个代码块
使用Lock接口的一般模式:
private final Lock lock = new ReentrantLock();
public void a() {
//获取锁
lock.lock();
//...执行需要同步的操作
//释放锁
lock.unlock();
}
Lock接口提供了另一个tryLock()方法来获取锁
线程如果不能通过tryLock()获取锁,tryLock()会立即返回,不会将线程进入休眠状态
应该注意的是当tryLock()方法返回false的时候程序不应该再执行临界区代码
读写锁:ReentrantReadWriteLock
是Lock的一个实现类,允许分离读和写操作,允许多个读线程和只有一个写线程
一般用法:
//读写锁
private ReadWriteLock lock = new ReentrantReadWriteLock();
//读操作
public void read() {
lock.readLock().lock();
//进行读的操作
lock.readLock().unlock();
}
//写操作
public void write() {
lock.writeLock().lock();
//进行写的操作
lock.writeLock().unlock();
}
线程进入读锁的前提条件:
没有其他线程的写锁,
没有写请求或者写请求的线程是持有该读锁的线程
线程进入写锁的前提条件:
没有其他线程的读锁
没有其他线程的写锁
wait()和notify()模式的替代品——await()和signalAll()
在生产者消费者模式中使用了wait()和notify(),现在用Lock接口来实现
一个Lock接口可能关联了一个或者多个条件,这些条件用Condition接口来抽象
Condition接口提供了线程的挂起和唤醒机制
Condition使用实例代码
//创建锁
private Lock lock = new ReentrantLock();
//创建关联条件
private Condition isFull = lock.newCondition();
private Condition isEmpty = lock.newCondition();
private int size = 2;
void get() {
//获取锁
lock.lock();
try {
//等待满足条件并接到唤醒通知
while (size == 0) {
isEmpty.await();
}
System.out.println("doGet when size == " + (size--));
isEmpty.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}
void set() {
//获取锁
lock.lock();
try {
//等待满足条件并接到唤醒通知
while (size == 2) {
isFull.await();
}
System.out.println("doSet when size == " + (size++));
isFull.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁
lock.unlock();
}
}
在调用condition的时候必须先获取congdition绑定的锁,所以condition的执行代码必须在lock()和unlock()之间
和wait()一样,condition.await()也会释放其绑定的锁