锁-未完成
2020/08/21
本文于
1601
天之前发表,文中内容可能已经过时。
操作系统级别如何实现锁
系统级别锁的实现
互斥锁
基本概念
互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。
自旋锁
基本概念
自旋锁是专为防止多处理器并发而引入的一种锁,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁。在多核环境下,操作系统通过锁内存总线这个机制保证锁的唯一性。
使用场景
只有在占用锁的时间极短的情况下,使用自旋锁才是合理的
注意事项
是递归使用一个自旋锁,即如果一个已经拥有某个自旋锁的CPU 想第二次获得这个自旋锁,则该CPU 将死锁。
java 级别如果实现锁
基本概念
调用操作系统
具体的实现
可重入锁
可重入锁的概念,持有锁的线程可以重复持有该锁。
自己实现的可重入锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| public class LocalReentrantLock {
private AtomicReference<Thread> owner; /** * 被获取的次数 */ private AtomicInteger counter;
private LinkedBlockingQueue<Thread> waitQueue;
public LocalReentrantLock() { //阻塞队列 waitQueue = new LinkedBlockingQueue(100); counter = new AtomicInteger(0); owner=new AtomicReference<>(); }
/** * 一直尝试获取锁 */ public void lock() { if (!tryLock()) { //如果获取不到锁,放入到等待队列 waitQueue.offer(Thread.currentThread()); while (true) { //取头部数据 Thread head = waitQueue.peek(); if (head == Thread.currentThread()) { //如果头部等于当前线程 if (!tryLock()) { //如果获取不到锁,说明是其它线程还占有的锁。挂起之后什么时候唤醒了,unlock的时候唤醒? LockSupport.park(); } else { //获取到了锁,直接弹出当前线程。 waitQueue.poll(); return; } } else { LockSupport.park(); } } } }
/** * 尝试获取锁,获取不到锁,直接返回false * * @return */ public boolean tryLock() { int count = counter.get(); if (count > 0) { if (owner.get() == Thread.currentThread()) { //拥有人是当前当前线程 counter.compareAndSet(count, count + 1); return true; } else { //把当前线程放到等待队列里面 return false; } } else { if (counter.compareAndSet(count, count + 1)) { //如果当前线程能够设置成1,设置所有人为当前现线程。 owner.set(Thread.currentThread()); return true; } else { //被其它的线程抢占,设置了,直接返回false return false; } } }
/** * 尝试解锁 */ public boolean tryUnlock() { int count = counter.get(); if (count > 0) { if (owner.get() != Thread.currentThread()) { throw new IllegalMonitorStateException("不能释放不是自己的锁"); } // 这里面不做多线程的考虑,因为上面已经保证了操作下面方法的肯定是拥有人线程。 count = count - 1; //设置引用次数减一 counter.set(count); if (count == 0) { owner.set(null); return true; } return false; } else { throw new IllegalMonitorStateException("锁已经释放"); } }
/** * 解除锁定 */ public void unlock() { if(tryUnlock()){ //先释放当前锁的拥有人,如果可以释放,唤醒头部线程。 Thread head= waitQueue.peek(); if(head!=null){ /** * 解锁头部线程 */ LockSupport.unpark(head); } } } }
|
测试用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static void main(String[] args) throws Exception { LocalReentrantLock localReentrantLock = new LocalReentrantLock(); localReentrantLock.lock(); Thread.sleep(1000l); System.out.println("主线程第一次获取锁"); new Thread(() -> { localReentrantLock.lock(); System.out.println("t1 线程第一次获取锁"); localReentrantLock.unlock(); System.out.println("t1 线程解锁他获取的锁"); }).start(); localReentrantLock.lock(); Thread.sleep(1000l); System.out.println("主线程第二次获取锁"); localReentrantLock.unlock(); System.out.println("主线程第一次释放锁"); localReentrantLock.unlock(); System.out.println("主线程第二次释放锁"); Thread.sleep(1000l); }
|
读写锁
分布式锁
实现方式
基于redis的实现方式
reddsion
基于zookeeper的实现方式
curator