Visibility problem

Visibility is a thread on the Shared variables, other threads can immediately see the Shared variables the updated value, which is a reasonable depending on the requirements, but in the case of multi-threaded, may let you down, since each CPU has its own cache, each thread used may be a different CPU, This leads to data visibility issues, starting with the following graph:

For a shared variable count, each CPU cache has a copy of count. Each thread can only operate on the copy of the shared variable count in its own CPU cache, but cannot directly operate on the copy of main memory or other CPU caches, which leads to data differences. A typical example of a problem with visibility in multithreading is the accumulation of variables, as in the following program:

public class Demo {

    private int count = 0;

    // Each thread is count + 10000
    public void add(a) {
        for (int i = 0; i < 10000; i++) {
            count += 1; }}public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i < 10; i++) {
            Demo demo = new Demo();
            Thread t1 = new Thread(() -> {
                demo.add();
            });
            Thread t2 = newThread(() -> { demo.add(); }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(demo.count); }}}Copy the code

We used two programs to accumulate the count variable, 10,000 times per thread. Logically, the final result should be 20,000 times, but after you execute it many times, you will find that the result is not necessarily 20,000 times, due to the visibility of the shared variable.

We started two threads, T1 and T2, and when the thread started, it would read the current main memory count into its CPU cache. The value of count could be 0 or 1 or whatever, we would default to 0, and each thread would execute count += 1. This is a parallel operation. CPU1 and CPU2 both have a count of 1 in their cache, and then they write the count from their cache back to main memory, which also has a count of 1, not 2, as we expected. The reason for this is data visibility.

Atomicity problem

Atomicity: An operation or operations, either all performed without interruption by any factor, or none performed at all. This atomicity is cpu-level, not atomicity in our Java code, like count += 1 in our visibility Demo; For example, this Java command will be compiled into the following three CPU instructions:

  • Load the variable count from memory into the CPU’s register, assuming count = 1
  • Perform count +1 in the register, count = 1+1 =2
  • Write the count after the result +1 to memory

This is a typical read, change, and write operation, but it is not atomic, because there is a competition between multiple cpus, not one CPU executes all the time, they are constantly preempting execution, release execution, so the above three instructions are not necessarily atomic. Here is the simulation flow of the count += 1 command for two threads:

After the CPU of thread 1 executes the first two instructions, the execution right is preempted by the CPU of thread 2. At this time, the CPU of thread 1 executes the execution right and waits for the execution right again. After the CPU of thread 2 obtains the execution right, it first reads the count from the memory. Thread 2’s CPU has just finished executing these three instructions, and then thread 2’s memory count is equal to 2, and thread 1 has the right to execute again, and thread 1 has only one command left to write count back to memory. After execution, the value of count in memory is still 2, not 3 as we expected.

Order problem

Orderliness: The order in which a program is executed is the order in which the code is executed, such as this code

1  int i = 1;
2  int m = 11;
3  long x = 23L;
Copy the code

The JVM will execute the code in whatever order the JVM compiler thinks is optimal to improve program efficiency, which may disrupt the order of code execution. It ensures that the result of the program’s final execution is the same as the result of the code’s sequential execution. This is also known as instruction reordering

A typical example of a program that is buggy due to instruction reordering is the double-check lock singleton without volatile.

public class Singleton { 
	static Singleton instance; 
	public static Singleton getInstance(a){ 
	// First judgment
	if (instance == null) { 
		Only one thread can acquire the lock
		synchronized(Singleton.class) { 
			// Second judgment
			if (instance == null) 
				// Build objects
				instance = newSingleton(); }}returninstance; }}Copy the code

The dual detection lock scheme looks perfect, but it is buggy in the actual run time, causing object escape problems and possibly getting an unfinished Singleton object. This is the problem of instruction reordering when building a Singleton object. Let’s first look at the instructions for constructing the ideal type of the object:

  • Instruction 1: Allocate a block of memory M;
  • Instruction 2: Initialize the Singleton object on memory M;
  • Instruction 3: Then M’s address is assigned to the instance variable.

This may not be the case on the JVM compiler and may be optimized for the following instructions:

  • Instruction 1: Allocate a block of memory M;
  • Instruction 2: Assign M’s address to the instance variable;
  • Instruction 3: Finally initialize the Singleton object on memory M.

It looks like a little optimization, a little optimization that makes your program unsafe, so let’s say the thread that grabbed the lock executes instruction 2, and then instance is no longer empty, and then there’s thread C, and thread C sees instance is no longer empty, Instance is not successfully initialized, and a null-pointer exception may be raised when a method or member variable of instance is called. Possible execution flowcharts:

These are the three causes of Java multithreading bugs, and the JDK also provides solutions to these problems, as shown in the figure below. We’ll discuss these solutions in more detail later.

Article insufficient place, hope everybody gives directions a lot, common study, common progress

The last

Play a small advertisement, welcome to scan the code to pay attention to the wechat public number: “The technical blog of the flathead brother”, progress together.