对于学习过数据库的来说,各种锁机制应该都不陌生吧,那你们知道悲观锁和排它锁基础概念是什么吗?它们又都该怎么实现呢?快一起来瞧瞧吧。
一、悲观锁概念及实现详解
悲观锁是一种数据库锁机制,它会总是假设最坏的情况,在每次线程去拿数据时都认为其他线程会修改数据,所以,每次在拿数据的时候它都会上锁,这样其他线程想拿这个数据就会一直阻塞,直到它拿到锁为止。
传统关系型数据库里就用到了很多这种锁机制,如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
悲观锁具体实现:
POJO类
class ProductStock { private Long productId; //商品id private Integer number; //库存量 public Long getProductId() { return productId; } public void setProductId(Long productId) { this.productId = productId; } public Integer getNumber() { return number; } public void setNumber(Integer number) { this.number = number; } }
实现类
/** * 更新库存(使用悲观锁) * @param productId * @return */ public boolean updateStock(Long productId) { //先锁定商品库存记录 ProductStock product = query("SELECT * FROM tb_product_stock WHERE product_id=#{productId} FOR UPDATE", productId); if (product.getNumber() > 0) { int updateCnt = update("UPDATE tb_product_stock SET number=number-1 WHERE product_id=#{productId}", productId); if (updateCnt > 0) { //更新库存成功 return true; } } return false; }
二、排它锁概念及实现详解
排他锁(X锁),又被叫做写锁、独占锁,这是一种基本的锁类型。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A。
排它锁具体实现:
lock锁实现
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; public class Mutex implements Lock { //创造一个同步器 //该同步器用一个state来维护,当state表示同一时间当前同步状态的线程数量 private static class Sync extends AbstractQueuedSynchronizer { @Override protected boolean tryAcquire(int arg) { if (compareAndSetState(0, arg)) { //CAS操作的原子性,若当前线程设置成1,其他线程无法设置成功 setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } @Override protected boolean tryRelease(int arg) { if (getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); //由于获取到了锁,因此这一步无需通过CAS操作保证原子性 return true; } //是否处于占用状态 @Override protected boolean isHeldExclusively() { return getState() == 1; } //返回一个Condition Condition newCondition() { return new ConditionObject(); } } private final Sync sync = new Sync(); //final域能保证在初始化之前只对一个线程可见 @Override public void lock() { sync.acquire(1); } @Override public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } @Override public boolean tryLock() { return sync.tryAcquire(1); } @Override public void unlock() { sync.release(1); } @Override public Condition newCondition() { return sync.newCondition(); } public boolean isLocked() { return sync.isHeldExclusively(); } //判断当前同步队列中是否还有等待获取锁 public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } }
自定义锁使用
import java.util.concurrent.locks.Lock; public class Test { public static void main(String[] args) { final Lock lock = new Mutex(); Thread t1 = new Thread(new Runnable() { @Override public void run() { lock.lock(); try { for (int i = 0; i < 10; i++) { try { System.out.println(Thread.currentThread() .getName() + "-" + i); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } finally { lock.unlock(); } } }, "Thread1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { lock.lock(); try { for (int i = 0; i < 10; i++) { try { System.out.println(Thread.currentThread() .getName() + "-" + i); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } finally { lock.unlock(); } } }, "Thread2"); t1.start(); t2.start(); } }
以上就是关于悲观锁及排它锁的所有内容了,如果还想了解更多锁机制相关的java常见问答知识,就请一直关注我们网站吧。
推荐阅读: