Lock接口和synchronized的比较
使用
private Lock lock = new ReentrantLock();
private int count =0;
public void docount() {//lock方法
lock.lock();
try {
count++;
} finally {
lock.unlock();//释放锁
}
}
public synchronized void docount2() {//直接加锁
count++;
}
单纯就使用而言,synchronized关键字更加简洁,且java基础关键字,更值得推荐
但遇到以下情况时,synchronized无法满足
获取锁可以被中断,超时获取锁,尝试获取锁,公平/非公平锁
此时应考虑使用lock关键字。
可重入锁ReentrantLock
当某个加锁方法递归调用自身时,需要重新得到锁
锁的公平和非公平
如果在时间上,先对锁进行获取的请求,一定先被满足,这个锁就是公平的,不满足,就是非公平的
非公平的效率一般来讲更高(加入有ABC三个线程,A先得到锁,B此时过来会处于被挂起状态,等到A释放锁,C刚好进来,如果是公平锁需要等到B从挂起状态被解除后获得锁,C还需要进入挂起状态。这相对于C直接获得锁相比效率是很慢的)
默认是非公平锁
ReadWriteLock接口和ReentrantReadWriteLock读写锁
ReentrantLock和Syn关键字,都是排他锁,
读写锁:同一时刻允许多个读线程同时访问,但是写线程访问的时候,所有的读和写都被阻塞,最适宜与读多写少的情况
private ReadWriteLock lock = new ReentrantReadWriteLock();
private Lock readLock = lock.readLock();//读锁
private Lock writeLock=lock.writeLock();//写锁
private String numb;
public String getNumb() {//get方法用于读
readLock.lock();
try {
return numb;
} finally {
readLock.unlock();//释放锁
}
}
public void setNumb(String numb) {//set写
writeLock.lock();
try {
this.numb = numb;
} finally {
writeLock.unlock();//释放锁
}
}
读写锁相对于一般的锁性能快很多
Condition接口
=线程的有选择等待通知模式=
我们知道用synchronized与wait()和notify()/notifyAll()方法结合可以实现等待/通知模式。但是,在使用notify()/notifyAll()方法进行通知时,被通知的线程却是由JVM随机选择的。为了摆脱这种窘境,Java在1.5引入了ReentrantLock和Condition类结合使用来达到有选择性的进行线程通知,在调度线程上更加灵活
=Object类中的wait()方法相当于Condition类中await()方法。
Object类中的wait(long time)方法相当于Condition类中await(long time,TimeUnit unit)方法。
Object类中的notify()方法相当于Condition类中signal()方法。
Object类中的notifyAll()方法相当于Condition类中signalAll()方法。=
还是一个关于快递员的粒子
public class ExpressCond {
public final static String CITY = "ShangHai";
private int km;/*快递运输里程数*/
private String site;/*快递到达地点*/
private Lock lock = new ReentrantLock();
private Condition keCond = lock.newCondition();
private Condition siteCond = lock.newCondition();
public ExpressCond() {
}
public ExpressCond(int km, String site) {
this.km = km;
this.site = site;
}
/* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
public void changeKm(){
lock.lock();
try {
this.km = 101;
keCond.signalAll();
}finally {
lock.unlock();
}
}
/* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
public void changeSite(){
lock.lock();
try {
this.site = "BeiJing";
siteCond.signal();
}finally {
lock.unlock();
}
}
/*当快递的里程数大于100时更新数据库*/
public void waitKm(){
lock.lock();
try {
while(this.km<=100) {
try {
keCond.await();
System.out.println("check km thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
System.out.println("the Km is "+this.km+",I will change db");
}
/*当快递到达目的地时通知用户*/
public void waitSite(){
lock.lock();
try {
while(CITY.equals(this.site)) {
try {
siteCond.await();
System.out.println("check site thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
System.out.println("the site is "+this.site+",I will call user");
}
}
private static ExpressCond express = new ExpressCond(0,ExpressCond.CITY);
/*检查里程数变化的线程,不满足条件,线程一直等待*/
private static class CheckKm extends Thread{
@Override
public void run() {
express.waitKm();
}
}
/*检查地点变化的线程,不满足条件,线程一直等待*/
private static class CheckSite extends Thread{
@Override
public void run() {
express.waitSite();
}
}
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<3;i++){//启三条处理目的地的线程,一直处于等待中,直到被唤醒
new CheckSite().start();
}
for(int i=0;i<3;i++){//启三条处理公里数的线程,一直等待,直到里程达到要求,被唤醒
new CheckKm().start();
}
Thread.sleep(1000);
express.changeKm();//快递里程变化
}