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

  • 相关阅读:
    10.25 测试
    ##2018-2019-1 20165327 《信息安全系统设计基础》第四周学习总结
    实验一 开发环境的熟悉
    ch03 课下作业——缓冲区溢出漏洞实验
    20165327 2018-2017-1 《信息安全系统设计基础》第三周学习总结
    week02 课堂作业
    第四周学习总结
    2018-2019-1 20165204 《信息安全系统设计基础》第三周学习总结
    2018-2019-1 20165204《信息安全系统设计基础》第二周学习总结
    2018-2019-1 20165204 《信息安全系统设计基础》第一周学习总结
  • 原文地址:https://www.cnblogs.com/GY8023/p/13693564.html
Copyright © 2011-2022 走看看