Article catalog
1, Atomicity
1.volatile problem
Code analysis:
package com.itheima.myvolatile; public class Demo { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); t1.setName("Path classmate"); t1.start(); MyThread2 t2 = new MyThread2(); t2.setName("Xiao pi"); t2.start(); } }
package com.itheima.myvolatile; public class Money { public static int money = 100000; }
package com.itheima.myvolatile; public class MyThread1 extends Thread { @Override public void run() { while(Money.money == 100000){ } System.out.println("The marriage fund is no longer 100000"); } }
package com.itheima.myvolatile; public class MyThread2 extends Thread { @Override public void run() { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } Money.money = 90000; } }
Procedural problem: Although the girl knows that the marriage fund is 100000, when the balance of the fund changes, the girl cannot know the latest balance.
2.volatile solution
Problems in the above cases:
When thread A modifies the shared data, thread B does not get the latest value in time. If the original value is still used, there will be A problem
1. Heap memory is unique. Each thread has its own thread stack.
2. When each thread uses variables in the heap, it will first copy a copy to the variable copy.
3. In the thread, each use is obtained from the copy of the variable.
Volatile keyword: force the thread to look at the latest value of the shared area every time it is used
Code implementation: using volatile keyword to solve
package com.itheima.myvolatile; public class Demo { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); t1.setName("Path classmate"); t1.start(); MyThread2 t2 = new MyThread2(); t2.setName("Xiao pi"); t2.start(); } }
package com.itheima.myvolatile; public class Money { public static volatile int money = 100000; }
package com.itheima.myvolatile; public class MyThread1 extends Thread { @Override public void run() { while(Money.money == 100000){ } System.out.println("The marriage fund is no longer 100000"); } }
package com.itheima.myvolatile; public class MyThread2 extends Thread { @Override public void run() { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } Money.money = 90000; } }
3.synchronized solution
synchronized solution:
1 . Thread obtains lock
2 . Empty variable copy
3 . Copy the latest value of the shared variable to the variable copy
4 . Execute code
5. Assign the value in the modified variable copy to the shared data
6 . Release lock
Code implementation:
package com.itheima.myvolatile2; public class Demo { public static void main(String[] args) { MyThread1 t1 = new MyThread1(); t1.setName("Path classmate"); t1.start(); MyThread2 t2 = new MyThread2(); t2.setName("Xiao pi"); t2.start(); } }
package com.itheima.myvolatile2; public class Money { public static Object lock = new Object(); public static volatile int money = 100000; }
package com.itheima.myvolatile2; public class MyThread1 extends Thread { @Override public void run() { while(true){ synchronized (Money.lock){ if(Money.money != 100000){ System.out.println("The marriage fund is no longer 100000"); break; } } } } }
package com.itheima.myvolatile2; public class MyThread2 extends Thread { @Override public void run() { synchronized (Money.lock) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } Money.money = 90000; } } }
4. Atomicity
Overview: the so-called atomicity means that in one operation or multiple operations, either all operations are executed and will not be interrupted by any factor, or all operations are not executed. Multiple operations are an inseparable whole.
Code implementation:
package com.itheima.threadatom; public class AtomDemo { public static void main(String[] args) { MyAtomThread atom = new MyAtomThread(); for (int i = 0; i < 100; i++) { new Thread(atom).start(); } } } class MyAtomThread implements Runnable { private volatile int count = 0; //Quantity of ice cream delivered @Override public void run() { for (int i = 0; i < 100; i++) { //1. Read data from shared data to this thread stack //2. Modify the value of the variable copy in the thread stack //3. The value of the variable copy in the thread stack will be assigned to the shared data count++; System.out.println("Already" + count + "Ice cream"); } } }
Code summary: count + + is not an atomic operation. It may be interrupted by other threads during execution
5.volatile keyword cannot guarantee atomicity
Solution: we can add locks to the count + + operation, so the count + + operation is the code in the critical area. The code in the critical area can only be executed by one thread at a time, so count + + becomes an atomic operation.
package com.itheima.threadatom2; public class AtomDemo { public static void main(String[] args) { MyAtomThread atom = new MyAtomThread(); for (int i = 0; i < 100; i++) { new Thread(atom).start(); } } } class MyAtomThread implements Runnable { private volatile int count = 0; //Quantity of ice cream delivered private Object lock = new Object(); @Override public void run() { for (int i = 0; i < 100; i++) { //1. Read data from shared data to this thread stack //2. Modify the value of the variable copy in the thread stack //3. The value of the variable copy in the thread stack will be assigned to the shared data synchronized (lock) { count++; System.out.println("Already" + count + "Ice cream"); } } } }
6. Atomicity_ AtomicInteger
Overview: java from jdk1 5 began to provide java util. concurrent. Atomic package (atomic package for short). The atomic operation class in this package provides a simple, efficient and thread safe way to update a variable. Because change
There are many types of quantities, so 13 classes are provided in the Atomic package, belonging to four types of Atomic update methods, namely, Atomic update basic type, Atomic update array, Atomic update reference and Atomic update attribute (field). This time we only explain
The Atomic package provides the following three classes:
AtomicBoolean: atomic update boolean type
AtomicInteger: atomic update integer
AtomicLong: atomic update long
The above 3 classes as like as two peas are provided, so this section is only explained by AtomicInteger. The common methods of AtomicInteger are as follows:
public AtomicInteger(): Initializes an atomic type with a default value of 0 Integer public AtomicInteger(int initialValue): Initializes an atomic type of the specified value Integer int get(): Get value int getAndIncrement(): Add 1 to the current value atomically. Note that the value before self increment is returned here. int incrementAndGet(): Add 1 to the current value atomically. Note that the value returned here is the value after self increment. int addAndGet(int data): Atomically compares the entered value with the value in the instance( AtomicInteger Inside value)Add and return the result. int getAndSet(int value): Set atomically to newValue And returns the old value.
Code implementation:
package com.itheima.threadatom3; import java.util.concurrent.atomic.AtomicInteger; public class MyAtomIntergerDemo1 { // public AtomicInteger(): Initializes an atomic Integer with a default value of 0 // public AtomicInteger(int initialValue): initializes an atomic Integer with a specified value public static void main(String[] args) { AtomicInteger ac = new AtomicInteger(); System.out.println(ac); AtomicInteger ac2 = new AtomicInteger(10); System.out.println(ac2); } }
package com.itheima.threadatom3; import java.lang.reflect.Field; import java.util.concurrent.atomic.AtomicInteger; public class MyAtomIntergerDemo2 { // int get(): Get value // int getAndIncrement(): atomically add 1 to the current value. Note that the value before self increment is returned here. // int incrementAndGet(): atomically add 1 to the current value. Note that the value returned here is the value after self increment. // int addAndGet(int data): Adds the parameter to the value in the object atomically and returns the result. // int getAndSet(int value): the value set atomically to newValue and returns the old value. public static void main(String[] args) { // AtomicInteger ac1 = new AtomicInteger(10); // System.out.println(ac1.get()); // AtomicInteger ac2 = new AtomicInteger(10); // int andIncrement = ac2.getAndIncrement(); // System.out.println(andIncrement); // System.out.println(ac2.get()); // AtomicInteger ac3 = new AtomicInteger(10); // int i = ac3.incrementAndGet(); // System.out.println(i);// Self increasing value // System.out.println(ac3.get()); // AtomicInteger ac4 = new AtomicInteger(10); // int i = ac4.addAndGet(20); // System.out.println(i); // System.out.println(ac4.get()); AtomicInteger ac5 = new AtomicInteger(100); int andSet = ac5.getAndSet(20); System.out.println(andSet); System.out.println(ac5.get()); } }
7.AtomicInteger - memory parsing
AtomicInteger principle: spin lock + CAS algorithm
CAS algorithm:
There are 3 operands (memory value V, old expected value A, value B to be modified)
When the old expected value A = = memory value, the modification is successful, and change V to B
When the old expected value A= Failed to modify the memory value at this time. No action will be taken
And retrieve the current latest value (this re acquisition action is spin)
8.AtomicInteger - source code analysis
Code implementation:
package com.itheima.threadatom4; public class AtomDemo { public static void main(String[] args) { MyAtomThread atom = new MyAtomThread(); for (int i = 0; i < 100; i++) { new Thread(atom).start(); } } }
package com.itheima.threadatom4; import java.util.concurrent.atomic.AtomicInteger; public class MyAtomThread implements Runnable { //private volatile int count = 0; // Quantity of ice cream delivered //private Object lock = new Object(); AtomicInteger ac = new AtomicInteger(0); @Override public void run() { for (int i = 0; i < 100; i++) { //1. Read data from shared data to this thread stack //2. Modify the value of the variable copy in the thread stack //3. The value of the variable copy in the thread stack will be assigned to the shared data //synchronized (lock) { // count++; // ac++; int count = ac.incrementAndGet(); System.out.println("Already" + count + "Ice cream"); // } } } }
Source code analysis:
//Self increment first, and then obtain the results after self increment public final int incrementAndGet() { //+1. Results after self increment //this represents the current atomicInteger (value) //1 self increment once return U.getAndAddInt(this, VALUE, 1) + 1; } public final int getAndAddInt(Object o, long offset, int delta) { //v old value int v; //Spin process do { //Keep getting old values v = getIntVolatile(o, offset); //If the return value of this method is false, continue to spin //If the return value of this method is true, the spin ends //o is the memory value //v old value //v + delta modified value } while (!weakCompareAndSetInt(o, offset, v, v + delta)); //Function: compare the values in memory and check whether the old values are equal. If they are equal, write the modified values to memory and return true. Indicates that the modification was successful. // If it is not equal, the modified value cannot be written to memory, and false is returned. Indicates that the modification failed. //If the modification fails, continue to spin. return v; }
9. Pessimistic lock and optimistic lock
The difference between synchronized and CAS:
**Similarities: * * in the case of multithreading, the security of shared data can be guaranteed.
**Differences: * * synchronized always starts from the worst point of view and thinks that each time data is obtained, others may modify it. Therefore, it will be locked before each operation to share data. (pessimistic lock)
cas is from an optimistic point of view, assuming that no one will modify the data every time it is obtained, so it will not be locked. However, when modifying shared data, you will check whether others have modified the data.
If others have modified it, I will get the latest value again.
If others haven't modified it, I can directly modify the value of shared data now (Le Guan lock)