Basic part: Java atomic component and synchronous component

Sneak on 2021-01-21 17:47:45
basic java atomic component synchronous


Preface

When using multithreaded concurrent programming , We often encounter modification operations on shared variables . At this point we can choose ConcurrentHashMap,ConcurrentLinkedQueue To store data safely . But if it's just about state modification , Thread execution order problem , Use Atomic The atomic component at the beginning or ReentrantLock、CyclicBarrier And so on , It would be a better choice , The principle and usage of them will be introduced one by one

  • The atomic principle of component implementation CAS
  • AtomicBoolean、AtomicIntegerArray The usage of atomic components 、
  • The implementation principle of synchronous component
  • ReentrantLock、CyclicBarrier And so on

Official account , Communicate together , Search on wechat : Sneak forward

The atomic principle of component implementation CAS

  • cas You can see an article written before : Explain the principle of lock in detail ,synchronized、volatile+cas Underlying implementation [1]

Application scenarios

  • Can be used to implement variables 、 Atomic operation of state in multithreading
  • Can be used to achieve synchronization lock (ReentrantLock)

Atomic components

  • Atomic operations of atomic components depend on the use of cas From the spin operation volatile variable-implemented
  • volatile The type variable of ensures that when the variable is modified , Other threads can see the latest value
  • cas Then guarantee value It's atomic manipulation , Will not be interrupted

Basic type atomic class

AtomicBoolean // Boolean type
AtomicInteger // Positive integer type
AtomicLong // Long integer type 
  • Examples of use
public static void main(String[] args) throws Exception {
AtomicBoolean atomicBoolean = new AtomicBoolean(false);
// Asynchronous thread modification atomicBoolean
CompletableFuture<Void> future = CompletableFuture.runAsync(() ->{
try {
Thread.sleep(1000); // Ensure that the asynchronous thread is modified after the main thread atomicBoolean by false
atomicBoolean.set(false);
}catch (Exception e){
throw new RuntimeException(e);
}
});
atomicBoolean.set(true);
future.join();
System.out.println("boolean value is:"+atomicBoolean.get());
}
--------------- Output results ------------------
boolean value is:false

Reference class, atomic class

AtomicReference
// Timestamped version of reference class atomic class
AtomicStampedReference
// amount to AtomicStampedReference,AtomicMarkableReference It's about
// Whether the variable is still the original variable , It doesn't matter if the middle has been modified
AtomicMarkableReference
  • AtomicReference The source code is as follows , It internally defines a volatile V value, With the help of VarHandle( The specific subclass is FieldInstanceReadWrite) Atomic operation ,MethodHandles Will help calculate value At the offset of the class , Last in VarHandle call Unsafe.public final native boolean compareAndSetReference(Object o, long offset, Object expected, Object x) Method atom modifies the properties of an object
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
private static final VarHandle VALUE;
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
private volatile V value;
....

ABA problem

  • Threads X Prepare to change the value of the variable from A Change it to B, However, during this time, the thread Y Change the value of the variable from A Change it to C, And then change to A; The last thread X The detection variable value is A, And replace with B. But actually ,A It's not the same anymore A 了
  • resolvent , It's about making variables unique . Value can be added with the version number , Or timestamps . If you add the version number , Threads Y The change to A1->B2->A3, The thread X If you update it again, you can judge A1 It's not equal to A3
  • AtomicStampedReference Implementation and AtomicReference almost , But the variable it modifies is volatile Pair<V> pair;,Pair Is its inner class .AtomicStampedReference It can be used to solve ABA problem
public class AtomicStampedReference<V> {
private static class Pair<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
private volatile Pair<V> pair;
  • If we don't care if the variables have been modified in the intermediate process , We only care whether the current variable is the original variable , You can use AtomicMarkableReference
  • AtomicStampedReference Use example of
public class Main {
public static void main(String[] args) throws Exception {
Test old = new Test("hello"), newTest = new Test("world");
AtomicStampedReference<Test> reference = new AtomicStampedReference<>(old, 1);
reference.compareAndSet(old, newTest,1,2);
System.out.println(" object :"+reference.getReference().name+"; Version number :"+reference.getStamp());
}
}
class Test{
Test(String name){ this.name = name; }
public String name;
}
--------------- Output results ------------------
object :world; Version number :2

Array atomic class

AtomicIntegerArray // integer array
AtomicLongArray // Long integer arrays
AtomicReferenceArray // Reference type array 
  • Inside the array atomic class, there will be an initial final Array of , It takes the entire array as an object , Then according to the subscript index Calculate the element offset , Call again UNSAFE.compareAndSetReference Perform atomic operations . The array is not volatile modification , To ensure that element types are visible in different threads , Get the element UNSAFEpublic native Object getReferenceVolatile(Object o, long offset) Method to get real-time element values
  • Examples of use
// The element is initialized to 0
AtomicIntegerArray array = new AtomicIntegerArray(2);
// Subscript to be 0 The elements of , It's expectation 0, The update value is 1
array.compareAndSet(0,0,1);
System.out.println(array.get(0));
--------------- Output results ------------------
1

Attribute atomic class

AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
AtomicReferenceFieldUpdater
  • If the operation object is a property of a certain type , have access to AtomicIntegerFieldUpdater Atomic updates , However, the properties of a class need to be defined as volatile Decorated variable , Ensure the visibility of this property in each thread , Otherwise, an error will be reported
  • Examples of use
public class Main {
public static void main(String[] args) {
AtomicReferenceFieldUpdater<Test,String> fieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Test.class,String.class,"name");
Test test = new Test("hello world");
fieldUpdater.compareAndSet(test,"hello world","siting");
System.out.println(fieldUpdater.get(test));
System.out.println(test.name);
}
}
class Test{
Test(String name){ this.name = name; }
public volatile String name;
}
--------------- Output results ------------------
siting
siting

accumulator

Striped64
LongAccumulator
LongAdder
//accumulatorFunction: Operational rules ,identity: Initial value
public LongAccumulator(LongBinaryOperator accumulatorFunction,long identity)
  • LongAccumulator and LongAdder All inherited from Striped64,Striped64 My main idea is to be with ConcurrentHashMap It's kind of similar , Piecewise calculation , When the concurrency performance of single variable computation is slow , We can spread mathematical operations across multiple variables , When you need to calculate the total value , Add it up one more time
  • LongAdder amount to LongAccumulator A special case implements
  • LongAccumulator An example of
public static void main(String[] args) throws Exception {
LongAccumulator accumulator = new LongAccumulator(Long::sum, 0);
for(int i=0;i<100000;i++){
CompletableFuture.runAsync(() -> accumulator.accumulate(1));
}
Thread.sleep(1000); // Waiting for all CompletableFuture Thread execution complete , Get more
System.out.println(accumulator.get());
}
--------------- Output results ------------------
100000

The implementation principle of synchronous component

  • java Most of the synchronization components maintain a state value internally , Like atomic components , When modifying the state value, it is generally through cas To achieve . And the maintenance of state modification is Doug Lea Abstract out AbstractQueuedSynchronizer(AQS) To achieve
  • AQS You can read an article written before : Explain the principle of lock in detail ,synchronized、volatile+cas Underlying implementation [2]

Synchronize components

ReentrantLock、ReentrantReadWriteLock

  • ReentrantLock、ReentrantReadWriteLock It's all based on AQS(AbstractQueuedSynchronizer) Realized . Because they have the distinction between fair lock and unfair lock , So there's no direct inheritance AQS, Instead, use inner classes to inherit , Fair lock and unfair lock are implemented separately AQS,ReentrantLock、ReentrantReadWriteLock With the help of inner classes to achieve synchronization
  • ReentrantLock Use example of
ReentrantLock lock = new ReentrantLock();
if(lock.tryLock()){
// Business logic
lock.unlock();
}
  • ReentrantReadWriteLock Use example of
public static void main(String[] args) throws Exception {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
if(lock.readLock().tryLock()){ // Read the lock
// Business logic
lock.readLock().unlock();
}
if(lock.writeLock().tryLock()){ // Write lock
// Business logic
lock.writeLock().unlock();
}
}

Semaphore Implementation principle and use scenarios

  • Semaphore and ReentrantLock equally , There are also fair and unfair competition lock strategies , It's also through internal class inheritance AQS To synchronize
  • Popular explanation : Suppose there's a well , There's no more than three people to draw water from . Everybody's getting water , You need to take a place . When all three positions are full , The fourth person needs to draw water , You have to wait for one of the first three to leave , To continue to get the location of the water
  • Examples of use
public static void main(String[] args) throws Exception {
Semaphore semaphore = new Semaphore(2);
for (int i = 0; i < 3; i++)
CompletableFuture.runAsync(() -> {
try {
System.out.println(Thread.currentThread().toString() + " start ");
if(semaphore.tryAcquire(1)){
Thread.sleep(1000);
semaphore.release(1);
System.out.println(Thread.currentThread().toString() + " No blocking ends ");
}else {
System.out.println(Thread.currentThread().toString() + " Blocked end ");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
// Guarantee CompletableFuture Threads are executed , The main thread ends again
Thread.sleep(2000);
}
--------------- Output results ------------------
Thread[ForkJoinPool.commonPool-worker-19,5,main] start
Thread[ForkJoinPool.commonPool-worker-5,5,main] start
Thread[ForkJoinPool.commonPool-worker-23,5,main] start
Thread[ForkJoinPool.commonPool-worker-23,5,main] Blocked end
Thread[ForkJoinPool.commonPool-worker-5,5,main] No blocking ends
Thread[ForkJoinPool.commonPool-worker-19,5,main] No blocking ends 
  • You can see three threads , Because the semaphore is set to 2, The third thread is unable to obtain information successfully , It will print the blocking end

CountDownLatch Implementation principle and use scenarios

  • CountDownLatch It depends on AQS Realize the synchronous operation of
  • Popular explanation : When playing games , If the main task needs to rely on the completion of five small tasks , When the main task can continue . You can use CountDownLatch, The mainline task is blocked and waiting , Every time you finish a small task , Just done One count , The main line cannot be triggered until all five small tasks are executed
  • Examples of use
public static void main(String[] args) throws Exception {
CountDownLatch count = new CountDownLatch(2);
for (int i = 0; i < 2; i++)
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println(" CompletableFuture over ");
count.countDown();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
// wait for CompletableFuture Thread completion
count.await();
System.out.println(" main over ");
}
--------------- Output results ------------------
CompletableFuture over
CompletableFuture over
main over 

CyclicBarrier Implementation principle and use scenarios

  • CyclicBarrier It depends on ReentrantLock lock and Condition trip Property to synchronize
  • Popular explanation :CyclicBarrier Need to block all threads to await state , Then all threads are awakened and executed . Imagine a railing blocking five sheep , When five sheep stand on the railing together , The railings will be pulled up , At this point, all the sheep can fly out of the pen
  • Examples of use
public static void main(String[] args) throws Exception {
CyclicBarrier barrier = new CyclicBarrier(2);
CompletableFuture.runAsync(()->{
try {
System.out.println("CompletableFuture run start-"+ Clock.systemUTC().millis());
barrier.await(); // Need to wait main The thread also executes to await State to continue execution
System.out.println("CompletableFuture run over-"+ Clock.systemUTC().millis());
}catch (Exception e){
throw new RuntimeException(e);
}
});
Thread.sleep(1000);
// and CompletableFuture Threads wait for each other
barrier.await();
System.out.println("main run over!");
}
--------------- Output results ------------------
CompletableFuture run start-1609822588881
main run over!
CompletableFuture run over-1609822589880

StampedLock

  • StampedLock Not with the help of AQS, It is to maintain multiple state values internally , And cooperate with cas Realized
  • StampedLock There are three modes : Write mode 、 Reading mode 、 Optimistic reading mode
  • StampedLock The read and write locks of can be converted to each other
// Get read lock , Spin acquisition , Returns a stamp value
public long readLock()
// Try reading lock , Unsuccessful return 0
public long tryReadLock()
// Unlock
public void unlockRead(long stamp)
// Get write lock , Spin acquisition , Returns a stamp value
public long writeLock()
// Try to add a write lock , Unsuccessful return 0
public long tryWriteLock()
// Unlock
public void unlockWrite(long stamp)
// Try reading a timestamp , And cooperate with validate Method to verify the validity of the timestamp
public long tryOptimisticRead()
// verification stamp Whether it works
public boolean validate(long stamp)
  • Examples of use
public static void main(String[] args) throws Exception {
StampedLock stampedLock = new StampedLock();
long stamp = stampedLock.tryOptimisticRead();
// Determine whether the version number is valid
if (!stampedLock.validate(stamp)) {
// Get read lock , It's idling
stamp = stampedLock.readLock();
long writeStamp = stampedLock.tryConvertToWriteLock(stamp);
if (writeStamp != 0) { // Successfully converted to write lock
//fixme Business operations
stampedLock.unlockWrite(writeStamp);
} else {
stampedLock.unlockRead(stamp);
// Try to get write read
stamp = stampedLock.tryWriteLock();
if (stamp != 0) {
//fixme Business operations
stampedLock.unlockWrite(writeStamp);
}
}
}
} 

Welcome refers to a mistake in the text

Reference article

  • Concurrent Striped64(l accumulator )[3]

Reference material

[1]

Explain the principle of lock in detail ,synchronized、volatile+cas Underlying implementation : https://juejin.cn/post/6854573210768900110

[2]

Explain the principle of lock in detail ,synchronized、volatile+cas Underlying implementation : https://juejin.cn/post/6854573210768900110

[3]

Concurrent Striped64(l accumulator ): https://www.cnblogs.com/gosaint/p/9129867.html

This article is from WeChat official account. - Sneak forward (qianxingcsc)

The source and reprint of the original text are detailed in the text , If there is any infringement , Please contact the yunjia_community@tencent.com Delete .

Original publication time : 2021-01-13

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[Sneak on]所创,转载请带上原文链接,感谢
https://javamana.com/2021/01/20210121174556312g.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云