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

原文地址:https://www.cnblogs.com/GY8023/p/13693564.html