1.ReentrantLock 与synchronized有相同的并发性和内存语义,还包含了中断锁等候和定时锁等候,意味着线程A如果先获得了对象obj的锁,那么线程B可以在等待指定时间内依然无法获取锁,那么就会自动放弃该锁。
2.但是由于synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否,而ReentrantLock使用代码实现的,系统无法自动释放锁,需要在代码中finally子句中显式释放锁lock.unlock();
3.使用建议:
在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案。
看下lock的具体使用,如下代码:
package thread.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 共享实体
*
* @author admin
*
*/
class Person {
public String name;
public String sex;
/*
* 默认是false。。 flag为false 生产者生产---消费者等待 flag为true 生产者等待---消费者消费
*/
public boolean flag = false;
Lock lock = new ReentrantLock();
}
/**
* 生产者
*
* @author admin
*
*/
class Write extends Thread {
int count = 0;
Person per = new Person();
Condition newCondition;
public Write(Person p, Condition newCondition) {
this.per = p;
this.newCondition = newCondition;
}
@Override
public void run() {
while (true) {
try {
// 开启锁
per.lock.lock();
if (per.flag) {
try {
newCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
if (count == 0) {
per.name = "yhl";
per.sex = "男";
} else {
per.name = "xyf";
per.sex = "女";
}
count = (count + 1) % 2;// 奇偶数计算
per.flag = true;// 设置为ture;让生产者等待,通知让消费者消费去
newCondition.signal();// 通知
}
} catch (Exception e) {
// TODO: handle exception
} finally {
per.lock.unlock();
}
}
}
}
/**
* 消费者
*
* @author admin
*
*/
class Read extends Thread {
Person per = new Person();
Condition newCondition;
public Read(Person p, Condition newCondition) {
this.per = p;
this.newCondition = newCondition;
}
@Override
public void run() {
while (true) {
try {
// 开启锁
per.lock.lock();
if (!per.flag) {
try {
newCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("name:" + per.name + ",sex:" + per.sex);
per.flag = false;// 设置为false 让消费者处于等待,生产者去生产
newCondition.signal();//通知
}
} catch (Exception e) {
// TODO: handle exception
} finally {
per.lock.unlock();
}
}
}
}
public class LockReadWrite {
public static void main(String[] args) {
Person p = new Person();
Condition newCondition = p.lock.newCondition();
Write w = new Write(p, newCondition);
Read r = new Read(p, newCondition);
w.start();
r.start();
}
}
总结来说,Lock和synchronized有以下几点不同:
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5)Lock可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择