zoukankan      html  css  js  c++  java
  • Java并发编程--锁

    根据分类标准我们把锁分为以下 7 大类别,分别是:

    1. 偏向锁/轻量级锁/重量级锁;
    2. 可重入锁/非可重入锁;
    3. 共享锁/独占锁;
    4. 公平锁/非公平锁;
    5. 悲观锁/乐观锁;
    6. 自旋锁/非自旋锁;
    7. 可中断锁/不可中断锁。

    以上是常见的分类标准,下面我们来逐一介绍它们的含义。

    偏向锁/轻量级锁/重量级锁

    这三种锁特指 synchronized 锁的状态,通过在对象头中的 mark word 来表明锁的状态。

    • 偏向锁

    如果自始至终,对于这把锁都不存在竞争,那么其实就没必要上锁,只需要打个标记就行了,这就是偏向锁的思想。一个对象被初始化后,还没有任何线程来获取它的锁时,那么它就是可偏向的,当有第一个线程来访问它并尝试获取锁的时候,它就将这个线程记录下来,以后如果尝试获取锁的线程正是偏向锁的拥有者,就可以直接获得锁,开销很小,性能最好。

    • 轻量级锁

    JVM 开发者发现在很多情况下,synchronized 中的代码是被多个线程交替执行的,而不是同时执行的,也就是说并不存在实际的竞争,或者是只有短时间的锁竞争,用 CAS 就可以解决,这种情况下,用完全互斥的重量级锁是没必要的。轻量级锁是指当锁原来是偏向锁的时候,被另一个线程访问,说明存在竞争,那么偏向锁就会升级为轻量级锁,线程会通过自旋的形式尝试获取锁,而不会陷入阻塞。

    • 重量级锁

    重量级锁是互斥锁,它是利用操作系统的同步机制实现的,所以开销相对比较大。当多个线程直接有实际竞争,且锁竞争时间长的时候,轻量级锁不能满足需求,锁就会膨胀为重量级锁。重量级锁会让其他申请却拿不到锁的线程进入阻塞状态。

    可重入锁/非可重入锁

    可重入锁指的是线程当前已经持有这把锁的状态下,能在不释放这把锁的情况下再次获取这把锁。

    非可重入锁指的是虽然当前线程持有了这把锁,但是想再次获取这把锁也必须先释放锁后才能再次尝试获取。

    /**
     * methodA 和methodB 都是同步方法,当线程进入 methodA 会获得该类的对象锁,
     * 在 methodA 对方法 methodB 做了调用,但是 methodB 也是同步的,因此该线程需要再次获得该对象锁。这期间其他线程无法获该对象锁。
     * 因此可重入性避免再次获取锁出现死锁的问题。
     */
    public class LockTest {
    
        public synchronized void methodA() {
            System.out.println("methodA");
            methodB();
        }
    
        public synchronized void methodB() {
            System.out.println("methodB");
        }
    }

    共享锁/独占锁

    共享锁指的是同一把锁可以被多个线程同时获得。

    独占锁指的是这把锁只能同时被一个线程获得。

    公平锁/非公平锁

    公平锁的公平的含义在于如果线程现在拿不到这把锁,那么线程就都会进入等待,开始排队,在等待队列里等待时间长的线程会优先拿到这把锁,有先来先得的意思。而非公平锁就不那么“完美”了,它会在一定情况下,忽略掉已经在排队的线程,发生插队现象。

    悲观锁/乐观锁

    悲观锁的概念是在获取资源之前,必须先拿到锁,以便达到“独占”的状态,当前线程在操作资源的时候,其他线程由于不能拿到锁,所以其他线程不能来影响我。
    乐观锁恰恰相反,它并不要求在获取资源前拿到锁,也不会锁住资源,乐观锁利用 CAS 理念,在不独占资源的情况下,完成了对资源的修改。
    悲观锁适合用于并发写入多、临界区代码复杂、竞争激烈等场景,这种场景下悲观锁可以避免大量的无用的反复尝试等消耗。
    乐观锁适用于大部分是读取,少部分是修改的场景,也适合虽然读写都很多,但是并发并不激烈的场景。在这些场景下,乐观锁不加锁的特点能让性能大幅提高。

    自旋锁/非自旋锁

    自旋锁的理念是如果线程拿不到锁,并不直接陷入阻塞或者释放CPU资源,而是开始利用循环不停的尝试获取锁。

    非自旋锁如果拿不到锁,直接放弃。可能会陷入阻塞或排队。

    可中断锁/不可中断锁

    可中断锁在获取锁的过程中,可以在中断去做其他的事情,不需要一直等到获取到锁才离开。ReentrantLock 是一种典型的可中断锁,例如使用 ReentrantLock.lockInterruptibly() 方法在获取锁的过程中不想获取了,那么可以调用 Thread.interrupt() 方法终止线程。

    不可中断锁一旦线程申请了锁,就只能等到拿到锁后才能进行其他的逻辑处理。synchronized 关键字修饰的锁代表不可中断锁。

  • 相关阅读:
    TopShelf注册win10 服务
    win 10服务简单注册
    关于Win10 的服务注册
    泛型 Generic
    数据转换成字符串格式
    蛋白粉怎么吃
    6 ways to Sort Pandas Dataframe: Pandas Tutorial
    GET and POST requests using Python
    python中安装包出现Retrying, 国内pip源提示“not a trusted or secure host”解决
    Anaconda 4.7.5
  • 原文地址:https://www.cnblogs.com/xxoome/p/13289846.html
Copyright © 2011-2022 走看看