What are the lockless technologies in Java to solve the concurrency problem? How to use it?

Keywords: Programming Java Database less JDK

In addition to using synchronized and Lock to Lock, there are many tool classes in Java that can solve concurrency problems without locking.

 

1. Atomic tools

In JDK 1.8, the classes under the java.util.concurrent.atomic package are all atomic classes, which are implemented based on sun.misc.Unsafe.

  • In order to solve the concurrency problem, CPU provides CAS instruction, full name is Compare And Swap, that is, compare and interact.
  • CAS instruction requires three parameters: variable, comparison value and new value. When the current value of a variable is equal to the comparison value, the variable is updated to the new value
  • CAS is a CPU instruction, which ensures atomicity at the CPU hardware level.
  • The atoms in java.util.concurrent.atomic package are divided into atomic basic data type, atomic object reference type, atomic array, atomic object attribute updater and atomic accumulator.

Atomic basic data types: AtomicBoolean, AtomicInteger, AtomicLong

Atomic object reference types: AtomicReference, AtomicStampedReference, AtomicMarkableReference

Atomic array: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray

Atomic object property update: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater

Atomic accumulator: doubleacumulator, DoubleAdder, LongAccumulator, LongAdder

 

Modify the class we used to test atomicity problems, and use a simple example of AtomicInteger.

package constxiong.concurrency.a026;

import java.util.concurrent.atomic.AtomicInteger;

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

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

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

		// 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 Add 10000 to end");
		});

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

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

		// Print count variable
		System.out.println(count.get());
	}

}

 

Print results as expected

thread t2 count plus 10000 ends
thread t1 count + 10000
20000

 

2. Thread local storage

  • The java.lang.ThreadLocal class is used for thread localized storage.
  • Thread localized storage is to create a variable for each thread. Only this thread can view and modify the value in this variable.
  • A typical example is that when spring deals with database transactions, it uses ThreadLocal to store its own database Connection for each thread.
  • When using ThreadLocal, please note that when not using the variable, you must call the remove() method to remove the variable, otherwise it may cause memory leakage.

 

Example

package constxiong.concurrency.a026;

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

	// Thread local store variable
	private static final ThreadLocal<Integer> THREAD_LOCAL_NUM = new ThreadLocal<Integer>() {
		@Override
		protected Integer initialValue() {//Initial value
			return 0;
		}
	};

	public static 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 variables
		}
	}
}

 

The last value of each thread is printed 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

 

3,copy-on-write

  • It can be seen from the English name that copying when writing is needed reflects a delay strategy.
  • The copy on write containers in Java include CopyOnWriteArrayList and CopyOnWriteArraySet.
  • It involves the full replication of arrays, so it also consumes more memory and is suitable for use when there is less writing.

 

This is a simple example of CopyOnWriteArrayList. It just shows how to use CopyOnWriteArrayList, and it is thread safe. This scenario is not suitable to use CopyOnWriteArrayList because it is more write than read.

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 the cowList
		for (int i = 0; i < 1000; i++) {
			Thread t = new Thread(() -> {
				for (int j = 0; j < 5; j++) {
					//Sleep for 10 milliseconds, and let the thread add integers to the cowList at the same time, which leads to 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());
	}
}

 

Print results

5000

 

If put

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

Change to

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

 

The printing result is an integer less than 5000.


       

Java interview question summary, there is always a stuck you!

Posted by soupy127 on Wed, 16 Oct 2019 06:09:17 -0700