显式锁

手动声明或释放锁,     synchronized为内置锁(非公平锁),并不是显式锁,synchronized不提供中断或者超时等方法,有局限性

1,如果没有用到Lock类的尝试获取锁tryLock()方法或者中断方法lockInterruptibly()时,尽量使用synchronized

2,synchronized占用的资源会相对较少,因为synchronized是语言的一个特性,但是显式锁Lock是一个类,要创建对象

显式锁使用规范

unlock()释放锁方法要放在finally里面,防止锁无法释放

	private Lock lock = new ReentrantLock();
......
	public void test() {
		lock.lock();
		try{
			age++;
		}finally {
			lock.unlock();
		}
	}
	
	public void test2() {
		lock.lock();
        try {
        	age--;
        } finally {
            lock.unlock();
        }
	}

可重入锁ReentrantLock:防止方法自己递归调用,让自己锁住自己,synchronized已经实现     new ReentrantLock()时候,默认非公平,可以传入参数已修改锁的类型(true为公平锁)

如果获取锁的顺序与请求锁的顺序相同,为公平锁,不过非公平锁性能会更好

非公平锁会插队,线程被唤醒的时候,上下文切换会消耗5000-10000的cpu时间,如果公平锁的话,每个线程都会有这个时间,会依次排队,这个时间就浪费了,非公平锁会利用上下文切换时去执行任务(当锁刚刚释放时,有一个线程刚好获取锁,锁会给他,省下上下文切换时间)

 

独占锁:不论线程做什么事,总会先拿到锁。

不过平时的业务大部分都是读多写少的情况,即数据基本上不需要修改,所以可以允许多个线程同时读,如果用独占锁,则只能同时一个线程读,大大影响了效率(数据库:读写分离

因此使用读写锁ReentrantReadWriteLock,这个类没有实现lock接口,实现的是ReadAndWrite接口

当读线程持有读锁,写线程不允许拿写锁,读线程可以拿读锁;如果写线程持有写锁,不论其他读还是写线程都不允许获取锁

写独占,读共享,读写互斥

能够极大提高效率

public class UseRwLock  implements GoodsService{

    private GoodsInfo goodsInfo;

    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock getLock = lock.readLock();//读锁
    private final Lock setLock = lock.writeLock();//写锁

    public UseRwLock(GoodsInfo goodsInfo) {
        this.goodsInfo = goodsInfo;
    }

    @Override
    public GoodsInfo getNum() {
        getLock.lock();
        try{
            SleepTools.ms(5);
            return this.goodsInfo;
        }finally {
            getLock.unlock();
        }
    }

    @Override
    public void setNum(int number) {
        setLock.lock();
        try{
            SleepTools.ms(5);
            goodsInfo.changeNumber(number);
        }finally {
            setLock.unlock();
        }
    }
}

public interface GoodsService {

	public GoodsInfo getNum();//获得商品的信息
	public void setNum(int number);//设置商品的数量
}


    public static void main(String[] args) throws InterruptedException {
        GoodsInfo goodsInfo = new GoodsInfo("Cup",100000,10000);
        GoodsService goodsService = new UseRwLock(goodsInfo);
        for(int i = 0;i<minthreadCount;i++){
            Thread setT = new Thread(new SetThread(goodsService));
            for(int j=0;j<readWriteRatio;j++) {
                Thread getT = new Thread(new GetThread(goodsService));
                getT.start();           	
            }
            SleepTools.ms(100);
            setT.start();
        }
    }

等待通知模式  

synchronized使用wait和notify

显示锁中使用Condition接口来实现,

Condition在lock接口中,Condition接口里的await,awaitUninterruptibly(),awaitNanos(),awaitUntil()方法相当于wait

Condition接口里的signal(),signalAll()方法相当于notify和notifyAll

写入锁提供了一个 Conditon 实现;读取锁不支持 Conditon ,readLock().newCondition() 会抛出 UnsupportedOperationException

public class ExpressCondOneLock {
    public final static String CITY = "ShangHai";
    private int km;/*快递运输里程数*/
    private String site;/*快递到达地点*/
    private Lock lock = new ReentrantLock();
    private Condition kmCond = lock.newCondition();
    private Condition siteCond = lock.newCondition();

    public ExpressCondOneLock() {
    }

    public ExpressCondOneLock(int km, String site) {
        this.km = km;
        this.site = site;
    }

    /* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
    public void changeKm(){
		lock.lock();
    	try {
    		this.km = 101;
    		kmCond.signal();//通知其他在锁上等待的线程
    	}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 {
        			kmCond.await();//当前线程进行等待
    				System.out.println("check km thread["+Thread.currentThread().getName()
    						+"] is be notify");
    			} 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(this.site.equals(CITY)) {
        		try {
    				siteCond.await();//当前线程进行等待
    				System.out.println("check Site thread["+Thread.currentThread().getName()
    						+"] is be notify");
    			} 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");
    }
}

 

最后修改于 2019-10-08 21:11:53
如果觉得我的文章对你有用,请随意赞赏
扫一扫支付
上一篇