In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
Today, I would like to share with you the relevant knowledge points of multithreading and high concurrency in Java concurrent programming. The content is detailed and the logic is clear. I believe most people still know too much about this knowledge, so share this article for your reference. I hope you can get something after reading this article. Let's take a look.
1.JMM data atomic operation
Read (read) ∶ reads data from main memory
Load (load): writes data read from main memory to working memory
Use (use): read data from working memory to calculate
Assign (assignment): reassigns the calculated value to the working memory
Store (storage): writes working memory data to main memory
Write (write): assigns past variable values of store to variables in main memory
Lock (locking): locks the main memory variable to identify it as thread exclusive
Unlock (unlock): unlock the main memory variable so that other threads can lock it
two。 Let's look at the volatile keyword.
(1) start two threads
Public class VolatileDemo {private static boolean flag = false; public static void main (String [] args) throws InterruptedException {new Thread (()-> {while (! flag) {} System.out.println ("out of the while loop";}) .start (); Thread.sleep (2000); new Thread (()-> changeFlage ()). Start () } private static void changeFlage () {System.out.println ("before starting to change threshold"); flag = true; System.out.println ("after changing threshold");}}
Before volatile is added, the while judgment of the first thread is always satisfied.
(2) after adding volatile to the variable flag
Public class VolatileDemo {private static volatile boolean flag = false; public static void main (String [] args) throws InterruptedException {new Thread (()-> {while (! flag) {} System.out.println ("out of the while loop";}) .start (); Thread.sleep (2000); new Thread (()-> changeFlage ()). Start () } private static void changeFlage () {System.out.println ("before starting to change threshold"); flag = true; System.out.println ("after changing threshold");}}
The while statement can satisfy the condition
(3) explanation of the principle:
When the first thread is started, the flag variable reads the data from the main memory through read, loads the data into the working memory of thread 1 using load, and reads flag into the thread through use; thread 2 does the same read operation. Thread 2 changes the value of flag through assign, thread 2 works the flag=true stored in memory, and then writes flag to the bus through store, and the bus writes flag to resident memory through write; because the two threads read the values in a variety of working memory, are copies of the main memory, and do not communicate with each other, thread one by one is recycled, and the flag of thread one is false.
After adding volatile, cache consistency protocol (MESI) is added. CPU senses the change of data through the bus sniffing mechanism, and the value in its own cache is invalid. At this time, the thread will invalidate the flag stored in working memory and re-read the value of flag from main memory. At this time, the while condition is met.
The bottom layer of volatile is modified by the lock of assembly language. When a variable is modified, it is immediately written back to the main class to avoid instruction reordering.
3. Three characteristics of concurrent programming
Visibility, orderliness, atomicity
4. Double lock judgment mechanism creates singleton pattern public class DoubleCheckLockSinglenon {private static volatile DoubleCheckLockSinglenon doubleCheckLockSingleon = null; public DoubleCheckLockSinglenon () {} public static DoubleCheckLockSinglenon getInstance () {if (null = = doubleCheckLockSingleon) {synchronized (DoubleCheckLockSinglenon.class) {if (null = = doubleCheckLockSingleon) {doubleCheckLockSingleon = new DoubleCheckLockSinglenon ();} return doubleCheckLockSingleon } public static void main (String [] args) {System.out.println (DoubleCheckLockSinglenon.getInstance ());}}
When a thread calls the getInstance method to create, first determine whether it is empty. If it is empty, add a lock to the object. Otherwise, a repeat will be created in the case of multithreading, and then the lock will again determine whether it is empty. When new an object, first allocate space in memory, then perform the zero operation of the object's init attribute, and then perform the initialization assignment operation.
In order to optimize the efficiency of code execution, cpu will reorder the code that meets the principles of as-if-serial and happens-before. If as-if-serial stipulates that the order of code execution within the thread does not affect the output of the result, it will reorder the instruction.
Happens-before specifies the order of some locks, and the unlock of the same object needs to appear before the next lock, etc.
So in order to prevent instruction rearrangement in new, first assign and then perform zero operation, you need to add volatile modifier, plus volatile modification, in new operation will create a memory barrier, high-speed cpu does not reorder instructions, the bottom is the lock keyword; memory barrier is divided into LoadLoad (read), storestore (write), loadstore (read and write), storeload (write read), the bottom is written by C++ code, C++ code is then called assembly language
5.synchronized keyword
(1) before adding synchronized
Package com.qingyun; / * Synchronized keyword * / public class SynchronizedDemo {public static void main (String [] args) throws InterruptedException {Num num = new Num (); Thread T1 = new Thread (()-> {for (int I = 0 Thread I < 1000000 Singapore +) {num.incrent ();}}); t1.start () For (int I = 0 num++; I < 1000000 public void incrent +) {num.incrent ();} t1.join (); System.out.println (num.getNum ());}} package com.qingyun; public class Num {public int num = 0; public void incrent () {num++;} public int getNum () {return num;}}
The output is not what we want, because the thread and the for loop add the method at the same time, so the final output is not what we want.
(2) after adding synchronized
Public synchronized void incrent () {num++;} / / or public void incrent () {synchronized (this) {num++;}}
The result of the output is what we want. The lock used at the bottom of the synchronized keyword is a heavyweight lock, a mutex lock, a pessimistic lock, a lock before jdk1.6, and the thread will be placed in a queue waiting for execution.
6.AtomicIntger atomic operation
(1) the operation of adding 1 to the atom can be implemented with AtomicInteger, and the performance is greatly improved compared with synchronized.
Public class Num {/ / public int num = 0; AtomicInteger atomicInteger = new AtomicInteger (); public void incrent () {atomicInteger.incrementAndGet (); / / Atomic plus 1} public int getNum () {return atomicInteger.get ();}}
The AtomicInteger source code has a value field, which is decorated with volatile, and the bottom layer of volatile is decorated with lock to ensure the correct result of multi-thread concurrency.
Private volatile int value
(2) what the atomicInteger.incrementAndGet () method does: first get the value of value, add 1 to the value, and then use the old value to compare with atomicInteger, and then set the newValue equally. because the values may not be equal to the use of multithreading, use while for circular comparison, equal to the end of execution.
While (true) {int oldValue = atomicInteger.get (); int newValue = oldValue+1; if (atomicInteger.compareAndSet (oldValue,newValue)) {break;}}
(3) the way to set a new value after atomicInteger.compareAndSet comparison is CAS: no lock, optimistic lock, lightweight lock, thread blocking in synchroznied, uplink switching, and time-consuming operating system scheduling. CAS is always more efficient than matching.
(4) the bottom layer of compareAndSetInt is modified by native, and the bottom layer is C++ code, which realizes the problem of atomicity. The use of code lock cmpxchqq in assembly language ensures atomicity and is a cache line lock.
(5) ABA problem: thread one and that to a variable, thread two executes relatively quickly, also get this variable, modify the value of the variable, and then quickly change back to the original value, so that the value of the variable has changed once, and when the thread executes compareAndSet again and again, although the value remains the same as before, it has already changed, and there is an ABA problem.
(6) the solution to the ABA problem is to add a version to the variable. Each operation variable version plus 1 dint JDK with a version lock has AtomicStampedReference, so that even if the variable is modified by other threads and then returns to the original value, the version number is not consistent.
7. Lock optimization
(1) the heavyweight lock will put the waiting thread in the queue, while the heavyweight lock will lock monitor, and there will be resource consumption for switching between the top and bottom. If there are too many threads in the lightweight lock, it will spin and consume cpu.
(2) after jdk1.6, the lock is upgraded to stateless-"biased lock (lock id specified) -" lightweight lock (spin expansion)-"heavyweight lock (queue storage)
(3) create an object, when the object is stateless, when a thread is started and another object is created, the bias lock is enabled, and the lock will not be released after the execution of the lock; when there are two threads to grab the object, the lock is immediately upgraded to a lightweight lock; when another thread is created to grab the object lock, it is upgraded from a lightweight lock to a heavyweight lock
(4) segmented CAS. There is a base record variable value at the bottom. When multiple thread classes access this variable, the value of base will be divided into multiple cell to form an array, and each cell corresponds to the cas processing of one or more threads to avoid thread spin idling. This is still a lightweight lock. When data is returned, the bottom layer calls the sum of all cell arrays and base.
Public class Num {LongAdder longAdder = new LongAdder (); public void incrent () {longAdder.increment ();} public long getNum () {return longAdder.longValue ();}} public long longValue () {return sum ();} public long sum () {Cell [] as = cells; Cell a; long sum = base If (as! = null) {for (int I = 0; I < as.length; + + I) {if ((a = as [I])! = null) sum + = a.value;}} return sum } these are all the contents of this article entitled "what are the knowledge points of multithreading and high concurrency in Java concurrent programming?" Thank you for reading! I believe you will gain a lot after reading this article. The editor will update different knowledge for you every day. If you want to learn more knowledge, please pay attention to the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.