synchronized和Lock有什么区别?
思路:
首先想到的应该是,synchronized是jvm层提供的关键字,是用来加锁的,而lock是Api层面提供的类,通过这个类来实现加锁的,这个从表面来看毋庸置疑;
再者就是,应为synchronized是jvm提供的关键字,用来进行防并发操作,所以不需要我们手动去释放锁,底层代码会进行实现,除非抛出异常;
那么lock因为是Api提供的外置类引用实现加锁操作的。所以肯定要进行手动的释放锁,否则没有底层进行释放,会进行死锁情况出现;这也是毋庸置疑
上述是从表面来看的
在用法上,synchronized既可以加在方法上,也可以加载特定的代码块上,括号中表示需要锁的对象,这都是正常写法,一般在方法里面进行synchronized关键字进行上锁,有时候加在方法上面锁方法。因为是jvm提供的,会由jvm进行托管
而Lock需要显示地指定起始位置和终止位置。毕竟是外部引入的,必须在方法体内,由代码指定;
可以回答:
-
synchronized是JVM层面实现的,java提供的关键字,Lock是API层面的锁。
-
synchronized不需要手动释放锁,底层会自动释放,
-
Lock则需要手动释放锁,否则有可能导致死锁
-
synchronized等待不可中断,除非抛出异常或者执行完成,抛出异常,jvm会自动要求释放锁。所以不存在死锁
-
Lock可以中断,通过interrupt()可中断
-
synchronized是非公平锁
-
Lock是默认公平锁,当传入false时是非公平锁
-
synchronized不可绑定多个条件
-
Lock可实现分组唤醒需要唤醒的锁
-
lock可以进行多线程拿到读锁,而写锁只有一个。读写分离
-
而synchronized只能单一化执行
Lock锁介绍:
在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景、高效的性能,java还提供了Lock接口及其实现类ReentrantLock和读写锁 ReentrantReadWriteLock。
相比synchronized来实现同步,使用Lock实现同步主要有以下差异性:
1、使用synchronized关键字时,锁的控制和释放是在synchronized同步代码块的开始和结束位置。而在使用Lock实现同步时,锁的获取和释放可以在不同的代码块、不同的方法中。这一点是基于使用者手动获取和释放锁的特性。
2、Lock接口提供了试图获取锁的tryLock()方法,在调用tryLock()获取锁失败时返回false,这样线程可以执行其它的操作 而不至于使线程进入休眠。tryLock()方法可传入一个long型的时间参数,允许在一定的时间内来获取锁。
3、Lock接口的实现类ReentrantReadWriteLock提供了读锁和写锁,允许多个线程获得读锁、而只能有一个线程获得写锁。读锁和写锁不能同时获得。实现了读和写的分离,这一点在需要并发读的应用中非常重要,如lucene允许多个线程读取索引数据进行查询但只能有一个线程负责索引数据的构建。
4、基于以上3点,lock来实现同步具备更好的性能。
Lock锁与条件同步:
与synchronized类似,Lock锁也可以实现条件同步。在java的concurrent包中提供了 Condition 接口及其实现类ConditionObject。
当满足一定条件时,调用Condition的await()方法使当前线程进入休眠状态进行等待。调用Condition的signalAll()方法唤醒因await()进入休眠的线程。
在synchronized与条件同步博文中,我们使用synchronized实现了一个生产者-消费者模型,在这里,来试试使用Lock锁及其同步条件来实现同样的一个生产者-消费者模型:
public class MessageStorageByLock {
private int maxSize;
private List<String> messages;
private final ReentrantLock lock;
private final Condition conditionWrite;//声明两个锁条件
private final Condition conditionRead;
public MessageStorageByLock(int maxSize) {
this.maxSize = maxSize;
messages = new LinkedList<String>();
lock = new ReentrantLock(true);//true修改锁的公平性,为true时,使用lifo队列来顺序获得锁
conditionWrite = lock.newCondition();//调用newCondition()方法,即new ConditionObject();
conditionRead = lock.newCondition();
}
public void set(String message){
//使用锁实现同步,获取所得操作,当锁被其他线程占用时,当前线程将进入休眠
lock.lock();
try{
while(messages.size() == maxSize){
System.out.print("the message buffer is full now,start into wait()\n");
conditionWrite.await();//满足条件时,线程休眠并释放锁。当调用 signalAll()时。线程唤醒并重新获得锁
}
Thread.sleep(100);
messages.add(message);
System.out.print("add message:"+message+" success\n");
conditionRead.signalAll();//唤醒因conditionRead.await()休眠的线程
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public String get(){
String message = null;
lock.lock();
try{
while(messages.size() == 0){
conditionRead.await();
System.out.print("the message buffer is empty now,start into wait()\n");
}
Thread.sleep(100);
message = ((LinkedList<String>)messages).poll();
System.out.print("get message:"+message+" success\n");
conditionWrite.signalAll();
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
return message;
}