多线程的学习 (六) 实现线程锁(ThreadLock)

1 锁

1.1什么是锁

所谓的锁,肯定是不想别人去拿到的东西才会上锁。那什么是锁呢?
我们可以稍微定义一下:确保同一时间同一对象操作同一资源的方法。

1.1 都有哪些锁?

既然我们稍微的定义了一下锁,那我们平时在编程中的时候又有哪些锁呢。部分举例一下,如有不全可以补充:
自旋锁: 线程状态及上下文切换消耗系统资源,当访问共享资源的时间短,频繁上下文切换不值得。jvm实 现,使线程在没获得锁的时候,不被挂起,转而执行空循环,循环几次之后,如果还没能获得锁,则被挂起 阻塞锁:阻塞锁改变了线程的运行状态,让线程进入阻塞状态进行等待,当获得相应的信号(唤醒或者时间) 时,才可以进入线程的准备就绪状态,转为就绪状态的所有线程,通过竞争,进入运行状态 。
重入锁: 支持线程再次进入的锁,就跟我们有房间钥匙,可以多次进入房间类似。
读写锁: 两把锁,读锁跟写锁,写写互斥、读写互斥、读读共享 互斥锁: 上厕所,进门之后就把门关了,不让其他人进来。
悲观锁: 总是假设坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上 锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
乐观锁: 每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别 人有没有去更新这个数据,可以使用版本号等机制。
公平锁: 大家都老老实实排队,对大家而言都很公平。
非公平锁: 一部分人排着队,但是新来的可能插队。
偏向锁: 偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时,持有偏向锁的 线程才会释放锁 独占锁:独占锁模式下,每次只能有一个线程能持有锁。
共享锁: 允许多个线程同时获取锁,并发访问共享资源。

1.2 如何使用锁

public static Lock lock = new ReentrantLock();

/**
 * 静态方法,直接对num计数器进行++操作。
 */
public static void inCreate() {

    lock.lock();
    num++;
    lock.unlock();
}

使用很简单,new一个锁,然后对需要枷锁的资源进行lock,在使用完成后需要unlock解锁操作就可以了。

1.3 lock与synchronized的区别

lock 获取锁与释放锁的过程,都需要程序员手动的控制 Lock用的是乐观锁方式。所谓乐观锁就是,每次不加 锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就 是 CAS操作 synchronized托管给jvm执行 原始采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味 着其他线程只能依靠阻塞来等待线程释放锁。
PS: 在过去synchronized一直是一个重操作,会降低系统的性能,所以一般都会使用lock,但是lock使用又没有synchronized方便,需要枷锁,解锁。如果稍微有点逻辑错误就会使得系统发生异常。但是在jdk1.5之后,几乎每个版本都在对synchronized进行优化,特别是1.6版本之后synchronized已经得到了很好的优化,与lock几乎没有什么性能差异,更别说现在13都快出来啦!!13都快出来啦!!13都快出来啦!!

2 实现锁。

实现一个简单的锁,我们要做到最低的要求。

  1. 能枷锁,能解锁。
  2. 可重入。
/**
 * @ClassName MyLock
 * @Description TODO 实现一个锁
 * @Author CabbageDevil
 * @Date 2019/7/9 16:46
 * @Version 1.0
 **/
public class MyLock implements Lock {
    /**
     * 上锁标识
     */
    private boolean isHoldLock = false;
    /**
     * 当前线程
     */
    private Thread holdLockThread = null;
    /**
     * 重入次数
     */
    private int reentryCount = 0;

    /**
     * 同一个时刻能且仅能有一个线程获取到锁
     * 其他线程只能等待该线程释放锁
     */
    @Override
    public synchronized void lock() {
        if (isHoldLock && Thread.currentThread() != holdLockThread) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        holdLockThread = Thread.currentThread();
        isHoldLock = true;
        reentryCount++;
    }


    @Override
    public synchronized void unlock() {
        //判断当前线程是否是持有锁的线程,是,重入次数减1。
        if (Thread.currentThread() == holdLockThread) {
            reentryCount--;
            if (0 == reentryCount) {
                notify();
                isHoldLock = false;
            }
        }


    }

    @Override
    public Condition newCondition() {
        return null;
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }
}

2.1 检查锁是否满足要求

这里我们要检查的是上面说的2点,加解锁的成功,是否重入。
加解锁的成功我们可以用我们以前写过的一个不安全实例,使用我们写的锁讲它变成线程安全的。
https://blog.csdn.net/BCDMW233/article/details/90653867

public static Lock lock = new MyLock();

/**
 * 静态方法,直接对num计数器进行++操作。
 */
public static void inCreate() {

    lock.lock();
    num++;
    lock.unlock();
}

这里我们还要写一个demo判断是否重入。

/**
 * @ClassName ReentryDemo
 * @Description TODO 重入demo
 * @Author CabbageDevil
 * @Date 2019/7/9 16:54
 * @Version 1.0
 **/
public class ReentryDemo {

    Lock lock =new MyLock();

    public void  methomdA(){
        lock.lock();
        System.out.println("A");
        methomdB();
        lock.unlock();
    }
    public void  methomdB(){

        lock.lock();
        System.out.println("B");
        lock.unlock();
    }

    public static void main(String[] args) {
        ReentryDemo reentryDemo = new ReentryDemo();
        reentryDemo.methomdA();
    }
}

这里我们的锁就完成了,当然你也可以用你自己的想法去实现一个锁,这两个demo也可以用来测试一下你的锁是否满足最低的标准。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值