Lock显示锁和Aqs——Condition接口和可重入锁,读写锁

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();//快递里程变化
    }

猜你喜欢

转载自blog.csdn.net/qq_41700030/article/details/101150695