常用到的多种锁(随时可能修改)
在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器)。为了性能,一个线程会在自己的memory中保持要访问的变量的副本。这样就会出现同一个变量在某个瞬间,在一个线程的memory中的值可能与另外一个线程memory中的值,或者main memory中的值不一致的情况。
violate 并不是锁,只是规定该变量不允许使用备份(缓存),只能从内存读写,但这并不说是线程安全的。
原因:Volatile一般情况下不能代替sychronized,因为volatile不能保证操作的原子性,即使只是i++,实际上也是由多个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但依然可能出现写入脏数据的情况。如果配合Java 5增加的atomic wrapper classes,对它们的increase之类的操作就不需要sychronized。
广义重入锁 递归调用的时候,同一线程能不能再次获得锁
ReentrantLock
- 没有线程持有锁的时候,state为0。
- 当某个线程获取锁时,state的值增加,具体增加多少开发人员可自定义,默认为1,表示该锁正在被一个线程占有。
- 当某个已经占用锁的线程再次获取到锁时,state再增长,此为重入锁。
- 当占有锁的线程释放锁时,state也要减去当初占有时传入的值,默认为1。
数据库悲观锁
update 或者手动获取锁(for update)
索引列是锁索引筛选到的列(无需全表扫描)
其他列锁表(全表扫描)
(多个查询条件也不影响上面的逻辑,所以库存扣减完全可以限制id+库存>0 来update获取行数)
乐观锁
需要自己实现,常用做法是记录一个递增的version,提交时候验证
Redis实现分布式锁
利用setIf来实现,网上提供的例子中,锁不能保证公平性,而且自定义的sleep容易导致线程堵死,加超时时间又和业务违背(请求失败)
目前没有发现好的策略
Zookeeper分布式锁
利用临时自增节点的特性,观察某个节点,然后每次有变化查看自己是不是最小的,如果是最小的,那么执行,不是最小的,继续等待。
这个性能上待测试
看到有错,麻烦指出谢谢!