Volatile

1. Ensure visibility

package com.chao.cvolatile;
import java.util.concurrent.TimeUnit;
public class JMMDemo {
    // If not volatile, the program will loop forever!
    // Volatile ensures visibility
    private volatile static int num = 0;
    public static void main(String[] args) { // main thread main


        new Thread(()->{Thread 1 is unaware of the main memory changes
            while(num==0){

            }
        }).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        num = 1; System.out.println(num); }}Copy the code

2,Atomicity is not guaranteed

Atomicity: ACID indivisible

Thread A cannot be interrupted or split while performing tasks. You either succeed at the same time or you fail at the same time.

package com.chao.tvolatile;
// Volatile does not guarantee atomicity
public class VDemo02 {
    // Volatile does not guarantee atomicity
    private volatile static int num = 0;
    public  static void add(a){
        num++;
    }
    public static void main(String[] args) {
        // In theory the num result should be 20,000
        for (int i = 1; i <=20; i++) {
            new Thread(()->{
                for (int j = 0; j <1000 ; j++) {
                    add();
                }
            }).start();
        }
        while(Thread.activeCount()>2) {//main gc
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + ""+ num); }}Copy the code

How can atomicity be guaranteed without locking and synchronized

Use atomic classes to solve atomicity problems

package com.chao.tvolatile;
import java.util.concurrent.atomic.AtomicInteger;
// Volatile does not guarantee atomicity
public class VDemo02 {
    // Volatile does not guarantee atomicity
    // Integer of the atomic class
    private volatile static AtomicInteger num = new AtomicInteger();
    public  static void add(a){
        //num++; // Not an atomic operation
        num.getAndIncrement(); //AtomicInteger + 1 method, the concurrency primitive of CAS CPU
    }
    public static void main(String[] args) {
        // In theory the num result should be 20,000
        for (int i = 1; i <=20; i++) {
            new Thread(()->{
                for (int j = 0; j <1000 ; j++) {
                    add();
                }
            }).start();
        }
        while(Thread.activeCount()>2) {//main gc
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + ""+ num); }}Copy the code

The bottom layers of these classes hook directly to the operating system! Modify values in memory! The Unsafe class is a very special existence!

Instruction rearrangement

What is instruction reordering: The computer does not execute the program you write.

Source code –> compiler optimizations –> instruction parallelism may also be rearranged –> memory systems –> execution

When the processor rearranges instructions, it considers the dependency between data.

int x = 1; / / 1
int y = 2; / / 2
x = x + 5; / / 3
y = x * x; / / 4What we expect:1234But maybe when you do it, it becomes2134 1324Could it be4123!Copy the code

Possible results: The default values of a, B, x, and y are 0

Thread A Thread B
x=a y=b
b=1 a=2

Normal result: x = 0; y = 0; But it may be due to reordering

Thread A Thread B
b=1 a=2
x=a y=b

Weird result caused by instruction rearrangement: x=2; y=1;

Non-computer major

Volatile prevents instruction reordering:

Memory barrier, CPU instructions. Function:

1, ensure the execution order of specific operations!

2. Memory visibility is guaranteed for certain variables (visibility is achieved using volatile)

Volatile can maintain visibility. Atomicity is not guaranteed. Thanks to the memory barrier, instruction reordering is guaranteed to be avoided!