1. VarHandle
1.1 用途
使用 VarHandle 取代 Unsafe
在 VarHandle 出现之前,这些潜在的问题会随着原子API的不断扩大而越来越遭。VarHandle 的出现替代了
java.util.concurrent.atomic
和sun.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)阻塞/唤醒线程;
synchronized
可以配合wait
和notify
实现线程在条件不满足时等待,条件满足时唤醒,用ReentrantLock
我们怎么编写wait
和notify
的功能呢?答案是使用
Condition
对象的await和signal
。
使用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