What lock-free technologies exist in Java to solve concurrency problems?How to use it?

Keywords: Programming Java Database less JDK

In addition to using synchronized, Lock locking, 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 based on the implementation of sun.misc.Unsafe.

  • To solve concurrency problems, the CPU provides CAS instructions, called Compare And Swap, that is, compare and interact
  • The CAS Directive requires three parameters, a variable, a comparison value, and a new value.Update a variable to a new value when its current value is equal to the comparison value
  • CAS is a CPU directive that guarantees atomicity at the CPU hardware level
  • Atoms in the java.util.concurrent.atomic package are classified as: atomic basic data types, atomic object reference types, atomic arrays, atomic object attribute updates, and atomic accumulators.

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: DoubleAccumulator, DoubleAdder, LongAccumulator, LongAdder

 

Modify our previous class for testing atomic problems, using a simple example of AtomicInteger

package constxiong.concurrency.a026;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * Testing Atomic Integer
 * 
 * @author ConstXiong
 */
public class TestAtomicInteger {

	// Count variable
	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 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();

		// Waiting for thread 1 execution to complete
		t1.join();
		// Waiting for thread 2 execution 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 plus 10000 end
20000

 

2. Thread Local Storage

  • The java.lang.ThreadLocal class is used for thread localized storage.
  • Thread localized storage is the creation of a variable for each thread in which only the thread can view and modify values.
  • A typical use case is when spring uses ThreadLocal to store each thread's own database Connection connection Connection when dealing with database transaction issues.
  • When using ThreadLocal, be aware that when you do not use the variable, you must call the remove() method to remove the variable, otherwise memory leaks may occur.

 

Example

package constxiong.concurrency.a026;

/**
 * Testing Atomic Integer
 * 
 * @author ConstXiong
 */
public class TestThreadLocal {

	// Thread Local Storage Variables
	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 was 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

  • According to the English name, it can be seen that write-time replication is required, which reflects a delay strategy.
  • The copy-on-write container in Java includes CopyOnWriteArrayList, CopyOnWriteArraySet.
  • It involves full replication of arrays, so it's also memory intensive and works well with fewer writes.

 

A simple example of CopyOnWriteArrayList, which just shows how CopyOnWriteArrayList is used and thread-safe.This scenario is not appropriate for using CopyOnWriteArrayList because it is written more and read less.

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, 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, letting the thread add integers to the 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());
	}
}

Print results

5000

 

If the

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

Change to

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

The printed result is an integer less than 5000

 

4. Other concurrent tool classes beginning with Concurrent, such as ConcurrentHashMap, ConcurrentLinkedDeque, ConcurrentLinkedQueue...


 

 

All Resource Resources Summarized on Public Number



 

Posted by cyanblue on Fri, 06 Dec 2019 02:18:00 -0800