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();
        }
    }
}

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

原文地址:https://www.cnblogs.com/turbo30/p/13688260.html