码迷,mamicode.com
首页 > 其他好文 > 详细

实现一个独占锁和3元共享锁及其思路

时间:2018-11-28 12:35:39      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:imp   should   dna   queue   support   自旋   stat   ide   线程   

public class SelfLock implements Lock{
    
    //state 表示获取到锁 state=1 获取到了锁,state=0,表示这个锁当前没有线程拿到
    private static class Sync extends AbstractQueuedSynchronizer{
        
        //是否占用
        protected boolean isHeldExclusively() {
            return getState()==1;
        }
        
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0,1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        
        protected boolean tryRelease(int arg) {
            if(getState()==0) {
                throw new UnsupportedOperationException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        
        Condition newCondition() {
            return new ConditionObject();
        }
    }
    
    private final Sync sycn = new Sync();

    @Override
    public void lock() {
        sycn.acquire(1);
        
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        sycn.acquireInterruptibly(1);
        
    }

    @Override
    public boolean tryLock() {
        return sycn.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sycn.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        sycn.release(1);
        
    }

    @Override
    public Condition newCondition() {
        return sycn.newCondition();
    }


}
public class Test {
    private static SelfLock sl = new SelfLock();

    private static int a = 0;
    private static Condition con = sl.newCondition();

    public static void increment() {
        sl.lock();
        a++;
        sl.unlock();
    }

    private static CyclicBarrier cb = new CyclicBarrier(31);// 设置一个同步屏障,等30个线程+主线程都执行完后再打印最终a的值

    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {

        for (int i = 0; i < 30; i++) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    for (int j = 0; j < 100000; j++) {
                        increment();
                    }
                    try {
                        cb.await();
                        //System.out.println(Thread.currentThread().getId() + " wo hao le");
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }).start();

        }
        cb.await();
        System.out.println(a);
    }
}

技术分享图片
public class TrinityLock   {

    //为3表示允许两个线程同时获得锁
    private final Sync sync = new Sync(3);

    private static final class Sync extends AbstractQueuedSynchronizer {
        //private static final long serialVersionUID = -7889272986162341211L;

        Sync(int count) {
            if (count <= 0) {
                throw new IllegalArgumentException("count must large than zero.");
            }
            setState(count);//设置3个许可证,最多允许3个共享线程
        }

        public int tryAcquireShared(int reduceCount) {
            for (;;) {
                int current = getState();
                int newCount = current - reduceCount;
                if (newCount < 0 || compareAndSetState(current, newCount)) {
                    return newCount;
                }
            }
        }

        public boolean tryReleaseShared(int returnCount) {
            for (;;) {
                int current = getState();
                int newCount = current + returnCount;
                if (compareAndSetState(current, newCount)) {
                    return true;
                }
            }
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }
    }

    public void lock() {
        sync.acquireShared(1);
    }

    public void unlock() {
        sync.releaseShared(1);
    }

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    public boolean tryLock() {
        return sync.tryAcquireShared(1) >= 0;
    }

    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
    }

    public Condition newCondition() {
        return sync.newCondition();
    }
}
三元共享锁

 

 

实现思路:一个锁的基本行为范式都定义在Lock接口中,我们只要实现Lock接口即可。lock接口中主要的lock和unlock方法的实现AQS已经帮我们实现大部分了,我们只要实现对state共享资源的细化操作就可以实现不同的锁也就是tryAcquire,tryRelease,tryAcquireShared,tryReleaseShared方法。

那么为啥我们只要实现上述4个方法就能实现不同的锁?

    比如:
    public void lock() {
        sycn.acquire(1);
        
    }

它的实现依赖于AQS中acquire方法 如下面代码

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

技术分享图片
 final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
acquireQueued

 

这里的tryAcquire就是我们重写的方法,我们重写的方法假如state为0,就将state置为1,并将当前线程设为独占线程,

假如state为1,返回false,然后addWaiter将当前线程置入同步队列的尾部,acquireQueued是自旋中,假如head节点指向了当前线程Node,就tryAcquire,返回interrupted值,然后根据条件值执行selfInterrupt阻塞当前线程。

总结:AQS为我们定义好了顶层的处理实现逻辑,我们在使用AQS构建符合我们需求的同步组件时,只需重写tryAcquire,tryAcquireShared,tryRelease,tryReleaseShared几个方法,来决定同步状态的释放和获取即可,至于背后复杂的线程排队,线程阻塞/唤醒,如何保证线程安全,都由AQS为我们完成了,这也是非常典型的模板方法的应用。AQS定义好顶级逻辑的骨架,并提取出公用的线程入队列/出队列,阻塞/唤醒等一系列复杂逻辑的实现,将部分简单的可由使用者决定的操作逻辑延迟到子类中去实现。

实现一个独占锁和3元共享锁及其思路

标签:imp   should   dna   queue   support   自旋   stat   ide   线程   

原文地址:https://www.cnblogs.com/ljjnbpy/p/10030018.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!