显式锁
手动声明或释放锁, 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");
}
}

