preface

In addition to the use of synchronized, Lock, Java there are many tools to solve concurrency problems without locking, of course, this is not without the boss summary of a concurrent programming practice notes, interested in concurrent programming you can also see.

Atomic tools

In JDK 1.8, Java. Util. Concurrent. Under the atomic package are atoms, atomic classes are based on the sun. The misc. Unsafe.

  • To solve the concurrency problem, the CPU provides the CAS instruction, which stands for Compare And Swap
  • The CAS instruction requires three parameters: variable, comparison value, and new value. A variable is updated to its new value only when its current value is equal to its comparison value
  • CAS is a CPU instruction guaranteed atomicity at the CPU hardware level
  • Java. Util. Concurrent. Atomic atoms in the package is divided into: basic data types, atomic atomic object reference type, atomic array, atomic object attribute updater and atomicity accumulator

Atomicity basic data types: AtomicBoolean, AtomicInteger, AtomicLong

Atomic object reference types: AtomicReference, AtomicStampedReference, and AtomicMarkableReference

Atomic arrays: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray

Atomic object attribute update: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater

Atomic accumulator: DoubleAccumulator, DoubleAdder, LongAccumulator, LongAdder

Modify the class we used to test the atomicity problem, using a simple example of AtomicInteger

package constxiong.concurrency.a026;

import java.util.concurrent.atomic.AtomicInteger;

/** * Test AtomicInteger **@author ConstXiong* /
public class TestAtomicInteger {

 // Count variables
 static volatile AtomicInteger count = new AtomicInteger(0);

 public static void main(String[] args) throws InterruptedException {
 Thread 1 adds 10000 to count
 Thread t1 = new Thread(() -> {
 for (int j = 0; j <10000; j++) {
 count.incrementAndGet();
 }
 System.out.println("Thread t1 count + 10000");
 });

 Thread 2 adds 10000 to count
 Thread t2 = new Thread(() -> {
 for (int j = 0; j <10000; j++) {
 count.incrementAndGet();
 }
 System.out.println("Thread t2 count + 10000");
 });

 // Start thread 1
 t1.start();
 // Start thread 2
 t2.start();

 // Wait for thread 1 to complete
 t1.join();
 Wait for thread 2 to complete
 t2.join();

 Print the count variableSystem.out.println(count.get()); }}Copy the code

The print results were as expected

Thread t2 count10000End Thread t1 count is added10000The end of the20000
Copy the code

Thread local storage

  • The java.lang.ThreadLocal class is used for thread localization storage.
  • Thread-local storage is the creation of a variable for each thread in which only the thread can view and modify the value.
  • A typical example is when Spring deals with database transactions and uses ThreadLocal to store individual database connections for each thread.
  • When using ThreadLocal, it is important to call remove() to remove the variable when it is not in use, otherwise it may cause memory leaks.

The sample

package constxiong.concurrency.a026;

/** * Test AtomicInteger **@author ConstXiong* /
public class TestThreadLocal {

 // Thread stores variables locally
 private static final ThreadLocal<Integer> THREAD_LOCAL_NUM = new ThreadLocal<Integer>() {
 @Override
 protected Integer initialValue() {/ / initial value
 return 0; }}; publicstatic void main(String[] args) {
 for (int i = 0; i <3; i++) {// Start three threads
 Thread t = new Thread() {
 @Override
 public void run(){ add10ByThreadLocal(); }}; t.start(); }}/** * thread local storage variable plus 5 */
 private static void add10ByThreadLocal() {
 try {
 for (int i = 0; i <5; i++) {
 Integer n = THREAD_LOCAL_NUM.get();
 n += 1;
 THREAD_LOCAL_NUM.set(n);
 System.out.println(Thread.currentThread().getName() + " : ThreadLocal num="+ n); }}finally {
 THREAD_LOCAL_NUM.remove();// Remove the variable}}}Copy the code

Each thread prints the last value up to 5

Thread-0 : ThreadLocal num=1
Thread-2 : ThreadLocal num=1
Thread-1 : ThreadLocal num=1
Thread-2 : ThreadLocal num=2
Thread-0 : ThreadLocal num=2
Thread-2 : ThreadLocal num=3
Thread-0 : ThreadLocal num=3
Thread-1 : ThreadLocal num=2
Thread-0 : ThreadLocal num=4
Thread-2 : ThreadLocal num=4
Thread-0 : ThreadLocal num=5
Thread-1 : ThreadLocal num=3
Thread-2 : ThreadLocal num=5
Thread-1 : ThreadLocal num=4
Thread-1 : ThreadLocal num=5
Copy the code

Third, the copy – on – write

  • According to the English name, you can see that the need to write copy, reflecting a delay strategy.
  • Java copy-on-write containers include CopyOnWriteArrayList and CopyOnWriteArraySet.
  • It involves a full copy of the array, so it is also memory intensive and is suitable for low write conditions.

Simple CopyOnWriteArrayList example, here is just to show how CopyOnWriteArrayList is used, and is thread safe. This scenario is not suitable for using CopyOnWriteArrayList because there is more writing and less reading.

package constxiong.concurrency.a026;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;

/** * test copy-on-write *@author ConstXiong* /
public class TestCopyOnWrite {

 private static final Random R = new Random();
 
 private static CopyOnWriteArrayList<Integer> cowList = new CopyOnWriteArrayList<Integer>();
// private static ArrayList<Integer> cowList = new ArrayList<Integer>();
 
 public static void main(String[] args) throws InterruptedException {
 List<Thread> threadList = new ArrayList<Thread>();
 // Start 1000 threads and add 5 random integers to cowList
 for (int i = 0; i <1000; i++) {
 Thread t = new Thread(() -> {
 for (int j = 0; j <5; j++) {
 // Hibernate for 10 milliseconds to allow the thread to add integers to cowList at the same time, causing concurrency problems
 try {
 Thread.sleep(10);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 cowList.add(R.nextInt(100)); }}); t.start(); threadList.add(t); }for(Thread t : threadList) { t.join(); } System.out.println(cowList.size()); }}Copy the code

Print the result

5000
Copy the code

If the

private static CopyOnWriteArrayList<Integer> cowList = new CopyOnWriteArrayList<Integer>();
Copy the code

Instead of

private static ArrayList<Integer> cowList = new ArrayList<Integer>();
Copy the code

The printed result is an integer less than 5000