重复造轮子(2) --自定义独占锁

最近刚刚通过了某大型游戏公司的技术面试,在和面试官交流中,主要都是谈及一些关于多线程开发中的锁原理。在以前的常规开发中,对于加锁操作而言经常会出现在多线程开发当中,所以对于锁的原理机制有必要花时间理一下,于是今晚写了这一篇文章。

队列同步器AbstractQueuedSynchronizer(AQS),这个东西似乎我们不经常用,但是它是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。

在以往的项目中我们有时候会用synchronized这个关键字来进行加锁,有的时候也会用jdk1.5之后出现的ReentrantLock来进行编写。主要还是看业务需求吧。

今天的案例是自己手写一个自定义独占锁,继承自lock接口,采用队列同步器来实现,以下是相应的代码部分:

首先是编写一个静态内部类Sync 继承自队列同步器,它在统一时刻只允许一个线程占有锁的资源,假如通过CAS设置同步状态为1以后,则表示同步状态设置成功了。

接下来便是代码部分的实现:

package com.sise.thread.Lock;

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

/**
 * 作者:idea
 * 日期:2018/6/25
 * 描述:自己手写独占锁
 */
public class Mutex implements Lock {
    private final Sync sync=new Sync();
    private static class Sync extends AbstractQueuedSynchronizer{
        //显示是否处于占用的状态
        protected boolean isHeldExclusively(){
            return getState()==1;
        }

        //尝试获取锁
        @Override
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0,1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        //释放锁
        @Override
        protected boolean tryRelease(int arg) {
            if(getState()==0)
                throw new IllegalMonitorStateException();
                setExclusiveOwnerThread(null);
                setState(0);
                return true;
        }
            //返回一个condition队列
        Condition newCondition() {
                return new ConditionObject();
        }

    }


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

    public boolean isLock(){
        return sync.isHeldExclusively();
    }

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

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

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

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

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

    public boolean hasQueuedThreads(){
        return sync.hasQueuedThreads();
    }
}

当这个独占锁的代码编写完成之后便是相应的测试部分了:

package com.sise.thread.Lock;


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 作者:idea
 * 日期:2018/6/25
 * 描述:测试独占锁
 */
public class TestMutex {

   public List list=new ArrayList();
   public Lock lock=new Mutex();

   public void insert(){
       try {
           lock.lock();
           for(int i=0;i<100;i++){
               list.add(i);
               Thread.sleep(10);
           }
           System.out.println(list.size());
       }catch (Exception e){
            e.printStackTrace();
       }finally {
           lock.unlock();
       }
   }

    public static void main(String[] args) {
        final  TestMutex t=new TestMutex();
        new Thread(){
            public void run(){
                t.insert();
            }
        }.start();
        new Thread(){
            public void run(){
                t.insert();
            }
        }.start();

    }
}

最终测试发现,两个线程的运行分别同被自定义的独占锁所保护,因此不会出现线程安全问题。
这里写图片描述

假设将锁去掉之后,控制台的数据可能就会出现不一样的结果了
这里写图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值