zoukankan      html  css  js  c++  java
  • JUC 自定义至多有2个线程获取同步状态的同步组件TwinsLock

    自定义同步组件 TwinsLock

    TwinsLock.java

    自定义简单的同步组件,该工具至多只允许2个线程同时访问,超过2个线程的访问将被阻塞,加入到同步队列中,这个自定义规则的工具为TwinsLock。
    由于允许2个线程同时获取同步锁,所以该同步组件是共享的。

    通俗的说:AQS是写同步的规则,而Lock接口是AQS的代理者,用Lock接口的实现方法去调用AQS的方法实现同步。AQS面向写同步规则的人,而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 TwinsLock implements Lock {
    
        private final Sync sync = new Sync(2); // 设置最多几个线程可以获取同步状态
    
        // 内部类 ,重写同步器中的共享相关的方法,(通俗的说AQS就是写锁的规则)
        private static final class Sync extends AbstractQueuedSynchronizer{
            Sync(int count) {
                if(count <= 0){
                    throw new IllegalArgumentException("count must large than zero");
                }
                setState(count); // 设置状态
            }
    
            // 尝试获取同步状态,state减
            @Override
            protected int tryAcquireShared(int reduceCount) {
                for(;;){
                    int current = getState(); // 获取当前AQS记录的状态
                    int newCount = current - reduceCount; // 得到新的状态
                    if(newCount < 0 || compareAndSetState(current, newCount)){
                        return newCount; 
                        // 返回值大于等于0表示获取成功,否则同步状态获取失败
                    }
                }
            }
    
            // 尝试释放同步状态,因为可能存在2个线程同时释放同步状态,
            // 为了保证安全,所以需要CAS保证原子性
            @Override
            protected boolean tryReleaseShared(int returnCount) {
                for(;;){
                    int current = getState();
                    int newCount = current + returnCount;
                    if (compareAndSetState(current, newCount)){
                        return true; // 返回true表示,同步释放成功
                    }
                }
            }
        }
    
        @Override
        public void lock() {
            /*状态加1,sync.acquireShared(1);这个方法是AQS里的方法,
            * 该方法会调用我们重写的tryAcquireShared(arg)方法,尝试获取锁,
            * 如果返回值小于0,则表示获取不成功,那么就会调用doAcquireShared(arg)
            * 方法,将该线程加入到队列中,以ACS方法加入队列,会无限循环直至加入队列成功*/
            sync.acquireShared(1);
        }
    
        @Override
        public void unlock() {
            /*状态减1,sync.releaseShared(1);会调用我们重写的tryReleaseShared(arg)
            * 方法,进行释放锁操作,直到释放锁成功,释放成功返回true,
            * 会调用doReleaseShared()方法唤醒后继节点*/
            sync.releaseShared(1);
        }
    
        @Override
        public void lockInterruptibly() throws InterruptedException {
            System.out.println("已中断");
        }
    
        @Override
        public boolean tryLock() {
            return false;
        }
    
        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            return false;
        }
    
        @Override
        public Condition newCondition() {
            return null;
        }
    }

    测试类 TwinsLockTest.java

    写一个测试类:

    import org.junit.Test;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Lock;
    
    public class TwinsLockTest {
    
        @Test
        public void test(){
            final Lock lock = new TwinsLock(); // 创建锁的实例
    
            // 写一个局部类,继承Thread
            class Worker extends Thread{
                @Override
                public void run() {
                    while (true){ // 无限循环获取锁,释放锁
                        lock.lock();
                        try {
                            TimeUnit.SECONDS.sleep(1);
                            System.out.println(Thread.currentThread().getName());
                            TimeUnit.SECONDS.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }finally {
                            lock.unlock();
                        }
                    }
                }
            }
    
            // 创建10个线程,去争夺锁,达到测试结果
            for (int i = 0; i < 10; i++){
                Worker worker = new Worker();
                worker.setDaemon(true); // 设置为守护线程
                worker.start();
            }
    
            // 该方法是每隔一秒进行一次换行,目的是打印结果好看,哈哈哈
            for (int i = 0; i < 10 ; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println();
            }
        }
    }

    通过打印结果,可以看出,的确每次只能有两个线程获取到了同步状态!其他线程获取失败,都会加入到队列中

  • 相关阅读:
    [原]使用ASP.NET MVC构建RESTful服务
    [原]ASP.NET MVC 3 使用 DotNetOpenAuth 实现SSO
    ASP.NET MVC + RESTful服务之HttpStatusResult
    [原]ASP.NET MVC 3 Razor 多国语言参考解决方案 补充三
    [原]ASP.NET MVC 3 使用jqGrid之TreeGrid
    [原]ASP.NET MVC 3 Razor 多国语言参考解决方案 补充
    vsftp
    对付CC攻击不必动用防火墙
    Symfony and Godaddy
    godaddy的VPS使用SSH登录的方法
  • 原文地址:https://www.cnblogs.com/turbo30/p/13688260.html
Copyright © 2011-2022 走看看