您当前的位置: 首页 >  Java

小志的博客

暂无认证

  • 1浏览

    0关注

    1217博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java并发多线程编程——使用AQS重写自己的锁代码示例

小志的博客 发布时间:2021-04-22 23:02:38 ,浏览量:1

一、使用AQS重写自己的锁代码示例
package com.xz.thread.t10;

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

/**
 * @description: 使用AQS重写自己的锁示例
 *               1、定义一个MyLock类,实现Lock, 说明MyLock已经是一个锁.
 *               2、定义一个继承AQS同步器的AqsSyn类,重写独占方式的锁
 *               3、MyLock类的获取锁或者释放锁交由AqsSyn同步器去完成,
 *                 因此,再使用同步器重写MyLock类里面的所有方法
 * @author: xz
 */
public class MyLock implements Lock {

    private AqsSyn aqsSyn =new AqsSyn();
    //定义一个继承AQS同步器的方法,可以重写独占模式或者共享模式的方法,此处lz重写独占模式的方法
    private class AqsSyn extends AbstractQueuedSynchronizer{
         //试图在独占模式下获取对象状态。
        @Override
        protected boolean tryAcquire(int arg) {
            /**
             * 如果第一个线程进来,可以拿到锁,因此我们可以返回true
             * 如果第二个线程进来,拿不到锁,返回false,
             * 有种特例,如果当前进来的线程和占用排它锁的线程是同一个线程(重入),则允许可以拿到锁,但是要更新状态值
             * */
            int state = getState();//获取锁的状态
            if(state==0) {//如果状态等于0 ,无状态(初始状态)
                if(compareAndSetState(0,arg)) {// 自动设置同步状态到给定的更新,如果状态等于0 ,将状态设置为arg
                    setExclusiveOwnerThread(Thread.currentThread());//设置占用排它锁的线程是当前线程
                    return true;
                }
            }else if(getExclusiveOwnerThread()==Thread.currentThread()){// 重入
                setState(state+1);//更新状态值
                return true;
            }
            return false;
        }

        //试图设置状态来反映独占模式下的一个释放。
        @Override
        protected boolean tryRelease(int arg) {
            //锁的获取和释放肯定是一一对应的,那么调用此方法的线程一定是当前线程,如果不是抛出异常
            if(Thread.currentThread()!=getExclusiveOwnerThread()) {
                throw new RuntimeException();
            }
            int state = getState()-arg;
            boolean flag = false;
            if(state==0) {//状态为0,释放锁
                setExclusiveOwnerThread(null);//设置占用排它锁的线程为空
                flag = true;
            }
            setState(state);
            return flag;
        }

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

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


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

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

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return aqsSyn.tryAcquireNanos(1,unit.toNanos(time));
    }
    @Override
    public void unlock() {
        aqsSyn.release(1);
    }
    @Override
    public Condition newCondition() {
        return aqsSyn.newCondition();
    }
}

二、测试使用AQS重写自己的锁是否产生线程安全性问题

1、代码

package com.xz.thread.t10;

/**
 * @description: 测试使用AQS重写自己的锁是否产生安全性问题
 * @author: xz
 */
public class Test {
    private int value;
    private  MyLock myLock =new MyLock();

    public int getValue(){
        myLock.lock();
        try {
            Thread.sleep(100);
            return value++;
        } catch (InterruptedException e) {
            throw new RuntimeException();
        }finally {
            myLock.unlock();
        }
    }

    public static void main(String[] args) {
        Test t =new Test();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    System.out.println(Thread.currentThread().getName()+"----"+t.getValue());
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    System.out.println(Thread.currentThread().getName()+"===="+t.getValue());
                }
            }
        }).start();
    }
}

2、输出结果 在这里插入图片描述 3、结论

  • 在使用AQS重写自己的锁情况下,同一个实例中多个线程获取的值不存在相同的情况。因此没有产生线程安全性问题。
三、测试使用AQS重写自己的锁是否可重入

1、代码

package com.xz.thread.t10;

/**
 * @description: 测试使用AQS重写自己的锁是否可重入
 * @author: xz
 */
public class Test2 {
    private  MyLock myLock =new MyLock();

    public void a(){
        myLock.lock();
        System.out.println("执行了a方法");
        b();
        myLock.unlock();
    }

    public void b(){
        myLock.lock();
        System.out.println("执行了b方法");
        myLock.unlock();
    }

    public static void main(String[] args) {
        Test2 t =new Test2();

        new Thread(new Runnable() {
            @Override
            public void run() {
                t.a();
            }
        }).start();
    }
}

2、输出结果 在这里插入图片描述 3、结论

  • 因为使用了AQS重写自己的锁,所以既能执行a方法,又能执行b方法;

  • 如果不使用重入锁,只会执行a方法;

关注
打赏
1661269038
查看更多评论
立即登录/注册

微信扫码登录

0.0421s