
在java中按照宏观认识上,一般分为乐观锁和悲观锁
乐观锁
通俗的讲就是某个操作读很多,写很少,遇到并发写入的情况非常少,大部分都是并发读,所以加锁就很不划算,但又不能杜绝这种情况,因此采用一种变通的方法来解决此问题,对某个数据的更新可以采用加版本号方法。比较本次的版本号和数据库的版本号是否一致,一致则更新,否则需要重新读取数据比较之后在写。
悲观锁
它与乐观锁刚好相反,读很少,容易出现并发写的情况,每次拿数据的时候都有可能已经不是最新的了,因此需要对该操作加锁,有且只有一个线程获得此锁,其它并发线程全部block住直到拿到锁。可以使用Synchronized对某个某方或者变量加锁,或者可以使用Lock对某片段代码加锁。
ReentrantLock类:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long var1, TimeUnit var3) throws InterruptedException;
void unlock();
Condition newCondition();
}
lock,unLock 对代码块加锁解锁,注意unlock必须写在finally里,可以当Synchronized使用。
tryLock方法可以判断是都能拿到锁
lockInterruptibly可以响应中断
ReentrantReadWriteLock 类:
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
Lock writeLock();
}
readLock可以实现多个线程同时读
writeLock只能有一个线程写
Lock和synchronized的选择
Lock和synchronized有以下几点不同:
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5)Lock可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
转自网友:http://www.cnblogs.com/dolphin0520/p/3923167.html
网友评论