zoukankan      html  css  js  c++  java
  • 实现reentrantlock和读写锁

    1 可以手动实现一个类似reentrantlock的工具,首先要维护一个state的标志,代表当前是否有线程已经使用资源。线程lock的时候,
    会用cas给state加1,其他线程检测状态。另外需要维护一个等待队列,争夺不到资源的线程统一挂起(park),等线程unlock的时候,
    标志减为0,同时从队列里挑一个线程unpark唤醒,继续得到资源操作;如果想让队列线程竞争,就都唤醒,最终只有一个得到资源。
    这是实现了基本的锁。
    public class LkLock {

    private ReentrantLock lock;


    private Thread ownerThread;

    private LinkedBlockingQueue<Thread> waitList = new LinkedBlockingQueue<Thread>(10000);

    private static Unsafe unsafe =null;


    private int state=0;

    private static long stateOffset;

    public LkLock(){
    try {
    Field f = Unsafe.class.getDeclaredField("theUnsafe"); //Internal reference
     f.setAccessible(true);
    unsafe = (Unsafe) f.get(null);
    stateOffset= unsafe.objectFieldOffset(LkLock.class.getDeclaredField("state"));
    } catch (Exception e) {
    System.out.println(e+" error");
    }
    }


    public void lock(){
    if(compareAndSetState(0,1)){
    ownerThread=Thread.currentThread();
    }else{
    acquire(1);
    }
    }

    public void unlock(){
    compareAndSetState(1,0);
    if(!CollectionUtils.isEmpty(waitList)){
    Thread t=waitList.poll();
    LockSupport.unpark(t);
    }

    }

    private void acquire(int i){
    try {
    //加入等待队列
     waitList.put(Thread.currentThread());
    //挂起
     LockSupport.park();
    } catch (InterruptedException e) {
    System.out.println(e);
    }
    }

    public int getState() {
    return state;
    }

    private boolean compareAndSetState(int src, int target){
    return unsafe.compareAndSwapInt(this, stateOffset, src, target);
    }

    }

    2  同样 如果想要实现能够重入的读写锁,读可重入,写唯一,并且读写互斥,那么需要用两个资源分别给读写的线程竞争,

    读的资源可累加,每次线程readlock的时候加一,不设上限;写的线程如上面只可唯一线程获得资源。并且无论读写线程竞争资源之前,

    都要检测对方资源是否已经被占用,如果占用也要挂起,这样可以达到互斥。改动如下 

    public void readLock(){
    if(writeState!=0){
    acquire();
    }
    if(compareAndSetReadState(readState,readState+1)){
    System.out.println(readState+" 读 我看到的 "+Thread.currentThread());
    }else{
    acquire();
    }
    }

    public void readUnlock(){
    compareAndSetReadState(readState,readState-1);
    if(!CollectionUtils.isEmpty(waitList)){
    while (waitList.size()!=0){
    Thread t=waitList.poll();
    LockSupport.unpark(t);
    }
    }

    }


    public void writeLock(){
    if(readState!=0){
    acquire();
    }

    if(compareAndSetWriteState(0,1)){
    System.out.println(writeState+" 写 我看到的 "+Thread.currentThread());
    }else{
    acquire();
    }
    }

    public void writeUnlock(){
    compareAndSetWriteState(1,0);
    if(!CollectionUtils.isEmpty(waitList)){
    while (waitList.size()!=0){
    Thread t=waitList.poll();
    LockSupport.unpark(t);
    }
    }

    }
  • 相关阅读:
    OC-内存管理-基本原理与引用计数器
    OC-改错题
    OC-Q&A
    OC-SEL
    CO-类的本质、description方法
    Tomcat 下 mysql的连接池配置和使用
    转:JAVA.NET.SOCKETEXCEPTION: TOO MANY OPEN FILES解决方法
    使应用程序常驻内存,不能被任务管理器关闭之配置文件设置
    解决Tomcat catalina.out 不断成长导致档案过大的问题
    >/dev/null 2>&1的含义
  • 原文地址:https://www.cnblogs.com/lkdirk/p/6627738.html
Copyright © 2011-2022 走看看