2019独角兽企业重金招聘Python工程师标准>>>
1、ReentrantLock 重入锁
ReentrantLock是Lock接口的实现类,ReentrantLock提供相对synchronized更为灵活的机制,有以下优点:
- 使用synchronized关键字时,只能在synchronized块结构中使用wait()、notify()等获取和释放控制。而使用Lock,获取和释放可以不在同一个块结构中;
- Lock接口提供了tryLock()方法,这个方法试图获取锁,如果锁已经被其他线程获取,它将返回false,并继续往下执行代码,而不会像synchronized一样阻塞等待。
- 相比synchronized,Lock的性能更好
public class Test {
public static void main(String[] args) {
PrintQueue printQueue = new PrintQueue();
for (int i = 0; i < 10; i++) {
new Thread(new Job(printQueue)).start();
}
}
}
class PrintQueue{
//声明锁对象并初始化
private final Lock queueLock = new ReentrantLock();
public void printJob(Object document){
//获取锁对象的控制
queueLock.lock();
Long duration = (long)(Math.random()*10000);
System.out.println(duration);
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//释放锁对象的控制
queueLock.unlock();
}
}
}
class Job implements Runnable{
private PrintQueue printQueue;
public Job(PrintQueue printQueue){
this.printQueue = printQueue;
}
@Override
public void run() {
printQueue.printJob(new Object());
}
}
Lock接口最主要的三个方法是:
- lock()方法,获取锁对象的控制,如果其他线程正在占用锁,会阻塞等待
- unLock()方法,释放锁对象的控制,必须要进行释放,否则会造成死锁
- tryLock()方法,尝试获取锁,如果当前其他线程正在占用锁,不会阻塞等待而会立刻返回false
2、ReentrantReadWirteLock 重入读写锁
ReentrantReadWirteLock是ReadWriteLock接口的实现类,这个类有两个锁,一个是读操作锁,一个是写操作锁。
- 其中使用读操作锁时可以允许多个线程同时访问,但是使用写操作锁时只允许一个线程进行
- 在一个线程执行写操作时,其他线程不能进行读操作
读写分离相对synchronized的情况大大提高了程序的效率。
使用ReentrantReadWriteLock时,主要有两个方法:
- readLock(),,然后可以调用lock、unLock、tryLock方法
- writeLock(),然后可以调用lock、unLock、tryLock方法
class PricesInfo{
private double price1;
private double price2;
//读写锁
private ReadWriteLock readWriteLock;
public PricesInfo(){
price1 = 1.0;
price2 = 1.0;
readWriteLock = new ReentrantReadWriteLock();
}
/**
* 获取读锁来获取数据
* @return
*/
public double getPrice1(){
//获取读锁
readWriteLock.readLock().lock();
double value = price1;
//释放读锁
readWriteLock.readLock().unlock();
return value;
}
public double getPrice2(){
readWriteLock.readLock().lock();
double value = price2;
readWriteLock.readLock().unlock();
return value;
}
public void setPrices(double price1,double price2){
//获取写锁
readWriteLock.writeLock().lock();
this.price1 = price1;
this.price2 = price2;
//释放写锁
readWriteLock.writeLock().unlock();
}
}
3、Lock的公平性
ReentrantLock和ReentrantReadWriteLock类都有一个boolean参数fair,默认值为false。
当fair = false时,为“非公平模式”,此时如果有多个线程在等待锁,锁将随机选择其中的一个线程。
当fair = true时,为“公平模式”,此时如果有多个线程在等待锁,锁将选择“已等待时间最长”的线程。
要修改fair值,只需使用重载的构造函数即可:
private Lock queueLock = new ReentrantLock(true);
4、在Lock中使用Condition的await()、signal()、signalAll()方法
Condition对象可以由Lock对象的newCondition()创建:
Lock lock = new ReentranLock();
//创建两个Condition对象
Condition con1 = lock.newCondition();
Condition con2 = lock.newCondition();
await()、signal()、signalAll()方法和Synchronized代码块中的wait()、notify()、notifyAll()方法类似,不同之处在于:
//下面这个语句只能唤醒因调用con1.await()而阻塞的线程
con1.signalAll();
//同理这个语句只能唤醒因con2.await()而阻塞的线程
con2.signalAll();