队列同步器和排它锁的简单实现

队列同步器

队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基础框架,它使用了一个int类型的成员变量来表示当前的同步状态,例如1表示有线程在占用锁,0表示没有线程占用该锁。它采用了FIFO的队列来实现。

拿独占锁来说,队列中有多个节点(Node),每个节点代表每个线程。而这个队列的头部(head)会放在一个同步器中,表示其头部正在占用该线程。
在这里插入图片描述
而其他的节点都会处于一个自旋的状态(其实就是一个for循环),以下列出同步队列器的源码。

/**
 * Acquires in exclusive uninterruptible mode for thread already in
 * queue. Used by condition wait methods as well as acquire.
 *
 * @param node the node
 * @param arg the acquire argument
 * @return {@code true} if interrupted while waiting
 */
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);
    }
}

每个非头结点的Node,会一直处于for循环中,判断这个锁是否被释放。当然,当head节点释放资源之后,head节点的next节点会取代head节点,其会加入到同步器中,占有这个锁。

排它锁的实现

package com.yangyang.thread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 要想创建一个锁,那么首先继承Lock接口,
 * 因为同步机制还需要同步队列来实现,保证其操作的原子性。
 * 因此我们还必须要创建一个内部类,来实现一个同步队列。
 */
public class Mutex implements Lock {

    /**
     * 我们在这里实现一个排他锁,因此我们必须要重写
     * tryAcquire(int arg):尝试获取同步状态(arg为1表示占用锁)
     * tryRelease(int arg):尝试释放同步状态
     * isHeldExclusively():是否处于占用状态
     */
    // 为什么要写成静态的内部类呢?因为我们在锁的时候肯定需要一个类属性来进行,不然每个对象都有一个没效果。
    private static class Syn extends AbstractQueuedSynchronizer{
        @Override
        protected boolean tryAcquire(int arg) {
            // 尝试占用锁,使用CAS(compareAndSwap)原子性的操作
            if(compareAndSetState(0,1)){
                // 操作成功,那么设置为独占锁
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            // 试图释放锁,如果当前状态为没有线程占用,那么抛出异常
            if(getState()==0) throw new IllegalThreadStateException();//
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        @Override
        protected boolean isHeldExclusively() {
            return getState()==1;
        }

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

    private final Syn syn = new Syn();

    /**
     * 请求一个独占锁
     */
    @Override
    public void lock() {
        syn.acquire(1);
    }

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

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

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

    @Override
    public void unlock() {
        syn.release(0);// 这个1参数没有意义,因为我们在重写的时候就没有使用到这个参数,但是书上是这么写的不知道是写错了还是怎么.
        // 所以我还是改为0吧,因为0表示这个没有获得同步状态。
    }

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

class TestMutex{
    public static void main(String[] args) {
        // 创建两个线程测试一下
        Mutex lock = new Mutex();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();//加锁
                try{
                    for (int i = 0 ; i < 10; i++){
                        System.out.println("t1   "+i);
                    }
                }finally {
                    lock.unlock();//释放锁
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();//加锁
                try{
                    for (int i = 0 ; i < 10; i++){
                        System.out.println("t2   "+i);
                    }
                }finally {
                    lock.unlock();//释放锁
                }
            }
        });
        t1.start();
        t2.start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值