zoukankan      html  css  js  c++  java
  • ReentrantLock、AQS源码学习笔记

    1. VarHandle

      1.1 用途

        使用 VarHandle 取代 Unsafe

        在 VarHandle 出现之前,这些潜在的问题会随着原子API的不断扩大而越来越遭。VarHandle 的出现替代了java.util.concurrent.atomicsun.misc.Unsafe的部分操作。并且提供了一系列标准的内存屏障操作,用于更加细粒度的控制内存排序。在安全性、可用性、性能上都要优于现有的API。VarHandle 可以与任何字段、数组元素或静态变量关联,支持在不同访问模型下对这些类型变量的访问,包括简单的 read/write 访问,volatile 类型的 read/write 访问,和 CAS(compare-and-swap)等。

        资料:

          Java 9 变量句柄-VarHandle  https://www.jianshu.com/p/e231042a52dd

      1.2 为什么unsafe不安全

        

        使用Unsafe几乎可以操作一切:

        (1)实例化一个类;

        (2)修改私有字段的值;

        (3)抛出checked异常;

        (4)使用堆外内存;

        (5)CAS操作;

        (6)阻塞/唤醒线程;

        
        资料:
          死磕 java魔法类之Unsafe解析  https://juejin.im/post/6844903838307057671
          Java魔法类:Unsafe应用解析   https://tech.meituan.com/2019/02/14/talk-about-java-magic-class-unsafe.html
     
     
    2. Condition
      资料:
        廖雪峰--使用Condition  https://www.liaoxuefeng.com/wiki/1252599548343744/1306581033549858
     
      

      synchronized可以配合waitnotify实现线程在条件不满足时等待,条件满足时唤醒,用ReentrantLock我们怎么编写waitnotify的功能呢?

      答案是使用Condition对象的awaitsignal

      使用Condition实现生产者消费者

      

    import java.util.*;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Main {
    
    
        public static void main(String[] args) {
            int size = 3;
            Person person = new Person(size);
    
            for (int i = 0; i < size; i++) {
                Thread c = new Thread(new Consumer(person, "消费者-" + i));
                c.start();
    
            }
    
            for (int i = 0; i < 5; i++) {
                Thread p = new Thread(new Producer(person, "生产者-" + i));
                p.start();
            }
    
    
        }
    }
    
    class Person{
        int maxSize;
        LinkedList<Integer> list;
        ReentrantLock lock = new ReentrantLock();
        Condition consumerCondition = lock.newCondition();
        Condition producerCondition = lock.newCondition();
    
        Person(int maxSize){
            this.maxSize = maxSize;
            list = new LinkedList<>();
        }
    
        public void consume(String name) throws InterruptedException {
            lock.lock();
    
            while (list.size() == 0){
                System.out.println(name + " -- wait");
                consumerCondition.await();
            }
            list.removeFirst();
            System.out.println(name + ": consume");
            producerCondition.signal();
            lock.unlock();
        }
    
        public void produce(String name) throws InterruptedException {
            lock.lock();
    
            while (list.size() == maxSize){
                System.out.println(name + " -- wait");
                producerCondition.await();
            }
    
            list.addLast(1);
            System.out.println(name + ": produce");
            consumerCondition.signal();
            lock.unlock();
        }
    }
    
    class Consumer implements Runnable{
        private final Person person;
        private final String name;
    
        public Consumer(Person person, String name) {
            this.person = person;
            this.name = name;
        }
    
        @Override
        public void run() {
            try {
                person.consume(name);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class Producer implements Runnable{
        private final Person person;
        private final String name;
    
        public Producer(Person person, String name) {
            this.person = person;
            this.name = name;
        }
    
        @Override
        public void run() {
            try {
                person.produce(name);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    3. ReentrantLock 没抢到锁的策略

      自旋几次,还未成功就调 LockSupport.park -> Unsafe.park 阻塞

      自旋操作

      第一次自旋:

        创建node

    node = new ExclusiveNode();

       第二次自旋:

        设置node属性并 tryInitializeHead();

                    node.waiter = current;
                    Node t = tail;
                    node.setPrevRelaxed(t);         // avoid unnecessary fence
                    if (t == null)
                        tryInitializeHead();
                    else if (!casTail(t, node))
                        node.setPrevRelaxed(null);  // back out
                    else
                        t.next = node;

      第三次自旋:

        将node入队

      

    t.next = node;

      第四次自旋:

        设置node状态

    node.status = WAITING;  

      第五次自旋:

        阻塞

                    long nanos;
                    spins = postSpins = (byte)((postSpins << 1) | 1);
                    if (!timed)
                        LockSupport.park(this);
                    else if ((nanos = time - System.nanoTime()) > 0L)
                        LockSupport.parkNanos(this, nanos);
                    else
                        break;
                    node.clearStatus();
                    if ((interrupted |= Thread.interrupted()) && interruptible)
                        break;        

      实验:debug: step into 红色行跟踪

      

    import java.util.concurrent.locks.ReentrantLock;
    
    public class Main{
    
        public static void main(String[] args) {
            ReentrantLock lock = new ReentrantLock();
            Thread t1 = new Thread(new A(lock));
            Thread t2 = new Thread(new B(lock));
            t1.start();
            t2.start();
        }
    }
    
    class A implements Runnable{
        private final ReentrantLock lock;
    
        public A(ReentrantLock lock) {
            this.lock = lock;
        }
    
        @Override
        public void run() {
            lock.lock();
            System.out.println("A locked");
        }
    }
    
    class B implements Runnable{
        private final ReentrantLock lock;
    
        public B(ReentrantLock lock) {
            this.lock = lock;
        }
    
        @Override
        public void run() {
            lock.lock();
            System.out.println("B locked");
        }
    }

    end

  • 相关阅读:
    hi.baidu.com 百度流量统计
    Autofac is designed to track and dispose of resources for you.
    IIS Manager could not load type for module provider 'SharedConfig' that is declared in administration.config
    How to create and manage configuration backups in Internet Information Services 7.0
    定制swagger的UI
    NSwag在asp.net web api中的使用,基于Global.asax
    NSwag Tutorial: Integrate the NSwag toolchain into your ASP.NET Web API project
    JS变量对象详解
    JS执行上下文(执行环境)详细图解
    JS内存空间详细图解
  • 原文地址:https://www.cnblogs.com/GY8023/p/13693564.html
Copyright © 2011-2022 走看看