• Java Lock


    Lock


    lock是一个JDK1.5提供的多线程接口,JDK API,位置就在java/util/concurrent/locks/下

    使用锁实现线程安全的关键在于,所有要共享资源的线程都必须使用一把锁,所以一般锁都会设为全局变量,如果设为局部变量就要注意可能每个线程在进入时都会去新建自己的锁从而是每个线程拥有的锁不是同一把而导致线程安全性操作失败

    比较

    • Lock需要显式地获得和释放锁,相对synchronized不需要显式地获取和释放锁更加繁琐,但lock更加灵活,
    • 也能够更方便实现线程公平性等其他操作
    • 可以非阻塞地获取锁
    • 能超时获取锁

    AQS(AbstractQueuedSynchronizer)

    JDK API文档中这样解释AQS,--非常重要
    为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架。此类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础。子类必须定义更改此状态的受保护方法,并定义哪种状态对于此对象意味着被获取或被释放。假定这些条件之后,此类中的其他方法就可以实现所有排队和阻塞机制。子类可以维护其他状态字段,但只是为了获得同步而只追踪使用 getState()、setState(int) 和 compareAndSetState(int, int) 方法来操作以原子方式更新的 int 值。
    -----------------------------翻译一下上面的话:AQS是为了使用一个FIFO等待队列的同步器来提供一个同步框架,具体实现的就是通过提供一份原子性的int值来实现的,线程的操作和状态都是通过这原子性的int来实现的,而要操作这个int呢,AQS提供了3个方法getState()、setState(int) 和 compareAndSetState(int, int)

    应该将子类定义为非公共内部帮助器类,可用它们来实现其封闭类的同步属性。类 AbstractQueuedSynchronizer 没有实现任何同步接口。而是定义了诸如 acquireInterruptibly(int) 之类的一些方法,在适当的时候可以通过具体的锁和相关同步器来调用它们,以实现其公共方法。

    此类支持默认的独占 模式和共享 模式之一,或者二者都支持。处于独占模式下时,其他线程试图获取该锁将无法取得成功。在共享模式下,多个线程获取某个锁可能(但不是一定)会获得成功。此类并不“了解”这些不同,除了机械地意识到当在共享模式下成功获取某一锁时,下一个等待线程(如果存在)也必须确定自己是否可以成功获取该锁。处于不同模式下的等待线程可以共享相同的 FIFO 队列。通常,实现子类只支持其中一种模式,但两种模式都可以在(例如)ReadWriteLock 中发挥作用。只支持独占模式或者只支持共享模式的子类不必定义支持未使用模式的方法。

    使用AQS

    AQS就是给我们维护了一个队列和状态,我们通过调用队列和状态来实现同步,其他的同步锁像Reentrantlock都是基础了AQS的类

    为了将此类用作同步器的基础,需要适当地重新定义以下方法,这是通过使用 getState()、setState(int) 和/或 compareAndSetState(int, int) 方>法来检查和/或修改同步状态来实现的:

    • tryAcquire(int) 获取--独自模式要实现的方法
    • tryRelease(int) 释放--独自模式要实现的方法
    • tryAcquireShared(int)--共享模式要实现的方法
    • tryReleaseShared(int)--共享模式要实现的方法
    • isHeldExclusively()--判断释放时是独占模式

    默认情况下,每个方法都抛出 UnsupportedOperationException。
    这些方法的实现在内部必须是线程安全的,通常应该很短并且不被阻塞。
    定义这些方法是使用此类的 唯一 受支持的方式。其他所有方法都被声明为final,因为它们无法是各不相同的。

    也就是说使用AQS你需要自定义一个

    锁的简单梳理

    • 偏向锁:偏行锁就是每次使用完之后不会像一般锁会立即释放锁,而是等待竞争出现,就是有别的线程在竞争时才会释放。

    • 轻量级锁:多个线程可以同时进入同步代码块,即多个线程能够同时获取锁。

    • 重入锁:比如有两个锁(两个synchronized块)当同一个线程拿到第一个锁的方法调用第二个方法时也可访问,而不是有了第一把锁就不能再次获得第二个方法的锁。即在遇到锁时判断锁的持有线程和当前线程是否是同一个线程

    • 自旋锁:在没有获得锁时,一致尝试获取锁

    • 共享锁

    • 独占锁

    • 排他锁

    • 读写锁:读写和写写互斥,读读不互斥,在同一线程中从读到写要锁升级即在释放读锁前要获得写锁,从写到读要锁降级,即在释放写锁前要先获得读锁

    • 公平锁:是否按请求的时间顺序执行

    • 非公平锁

    • 死锁:相互竞争导致所有的线程谁都无法获得锁,进而没有一个线程能执行

    • 活锁:相互礼让导致没有线程得到锁,进而没有一个线程能执行

    本博客为Swagger-Ranger的笔记分享,文中源码地址: https://github.com/Swagger-Ranger
    欢迎交流指正,如有侵权请联系作者确认删除: liufei32@outlook.com

  • 相关阅读:
    Codeforces
    Codeforces
    SCUT
    Codeforces
    Codeforces
    poj 2229 Sumsets(类似于n的m划分)
    poj 1742 Coins(多重背包)
    hdu 2159FATE(完全背包)
    NOIP 普及组 2014 比例简化
    2018.10.2浪在ACM 集训队第三次测试赛
  • 原文地址:https://www.cnblogs.com/Swagger-Ranger/p/10669919.html
Copyright © 2020-2023  润新知