java中为了解决多线程并发带来的线程安全问题,引入了锁机制。
一、公平锁和非公平锁
1、公平锁:按照申请锁的顺序(FIFO队列)来获取锁。
2、非公平锁:所有线程都会竞争,获取的锁的顺序和申请顺序无关。
ReentrantLock failReentrantLock = new ReentrantLock(true); //公平锁
ReentrantLock unFairReentrantLock = new ReentrantLock(); // 非公平锁
二、共享锁和独占锁
1、共享锁:又称读锁,支持多个线程同时获取锁,可以读数据,无法更新。
2、独占锁:又称写锁,一次只能由一个线程访问。可以更新数据。
ReadWriteLock readWriteLock = new ReadWriteLock() {
@Override
public Lock readLock() { return null; } @Override public Lock writeLock() { return null; }
};
三、乐观锁和悲观锁
1、乐观锁:每次获取数据不认为会有其他线程修改数据,乐观的认为不会产生并发问题。因此在读数据时候不会加锁,但在更新时候会check其他线程有没有对数据进行过修改。
check方式一般有两种:(1)版本号机制 (2)cas操作
对于版本号机制,会为数据加上一个版本号字段(version),每更新一次数据,version+1。如果线程要更新数据值,会读取数据和对应version。提交更新时,
如果version和数据在数据库中version 一致则更新,否则重试。 sql:
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
对于cas操作:即compare and set,涉及三个操作数,数据所在的内存值,预期值,新值。如果更新数据,会check内存值和之前取到的值是否相等,如果相等用新值更新,否则
自旋,即不断重试。
2、悲观锁:每次获取数据认为会有其他线程修改数据,悲观的认为一定会产生并发问题。因此每次获取数据之前都会加锁。比如java中 synchronized。