This is the 24th day of my participation in the August Text Challenge.More challenges in August

Multithreading and high concurrency

1. Synchornized keyword

1. Data synchronization caused by multiple threads accessing the same resource:

  1. Solution: Lock a resource, that is, lock an object. The lock object cannot be String, Integer, Long (basic data type).
package com.anzhi;

import java.util.concurrent.TimeUnit;

public class Thread_base implements Runnable{

    private Integer count = 10;
    @Override
    public /*synchronized*/ void run(a) {  Synchronized (this) is equivalent to synchronized(this) at runtime, and t.class when modifying static methods
        count--;
        System.out.println(Thread.currentThread().getName()+"-"+count);
    }

    public static void main(String[] args) {
        Thread_base t1 = new Thread_base();
        for(int i=0; i<10; i++){
            count--;
            new Thread(t1,"t1").start(); }}}Copy the code

Synchronized has no underlying locking implementation requirements and is not regulated by the JVM.

Synchronized is a reentrant lock

package com.anzhi;

public class Thread_base1 implements Runnable{

    private Integer count = 10;
    @Override
    public synchronized void run(a) {
        count--;
        System.out.println(Thread.currentThread().getName()+"-"+count);
        test();
    }

    public synchronized void test(a){
        System.out.println("Reentrant call...");
    }

    public static void main(String[] args) {
        Thread_base1 t1 = new Thread_base1();
        for(int i=0; i<10; i++){
            new Thread(t1,"t1").start(); }}}Copy the code

Locked and unlocked methods run simultaneously

Exercise: Simulating a bank account:

1. Lock the service write method.

2. Be open to business reading methods

3. Is this ok?

package com.anzhi;

import java.sql.Time;
import java.util.concurrent.TimeUnit;

public class Account {
    private String name;
    private double money;

    public synchronized void set(String name, double money){
        this.name = name;
        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.money = money;
    }

    public/*synchronized*/ void get(String name){  // The lock method and the lock method are run simultaneously
        System.out.println("name----"+this.name+" money---"+this.money);
    }


    public static void main(String[] args) {
        Account account = new Account();
        new Thread(()->{
            account.set("zhangsan".1000.0);
        }).start();

        try {
            TimeUnit.MICROSECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.get("zhangsan");

        try {
            TimeUnit.MICROSECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        account.get("zhangsan"); }}Copy the code

Exception lock: If an exception occurs, the lock will be released

package com.anzhi;

public class Thread_base2{

    private Integer count = 10;

    public synchronized void run(a) {
        while(true) {
            count--;
            if(count == 5) {int i = 1/0;
            }
            System.out.println(Thread.currentThread().getName() + "-"+ count); }}public static void main(String[] args) {
        Thread_base2 t1 = new Thread_base2();
        new Thread(()->{
            t1.run();
        }).start();

        Runnable t2 = new Runnable() {
            @Override
            public void run(a) { t1.run(); }};new Thread(t2,"t2").start(); }}Copy the code

Synchronized low-level implementation:

1. Early JDK: heavier-OS

2. Concept of lock upgrade:

When there is no thread contention, markdown records the thread ID (biased lock). When there is another thread contention, the biased lock is upgraded to spin lock, spin in place, wait, default 10 times. After 10 times, there is still no resource acquisition, upgraded to heavyweight lock, join the wait queue, no longer occupy CPU.Copy the code
  1. Usage scenarios of locks
Locking code execution time is long, the number of threads, the use of system lock; Execute code time end, thread number is small, use spin lock;Copy the code

2. volatile

role

Ensure visibility of threads; Disallow instruction reordering; DCL singleton: Double Check LockCopy the code

Verify visibility

Each thread has its own workspace,

The process of modifying A value in memory is to copy A copy from memory – “workspace modification -” and return the value to memory (refresh memory), but after A modification, B will continue to loop if it is not read from the inner space again, which is invisible between threads. With volatile, B is notified as soon as A changes its value

package com.anzhi.voliate;

import java.util.concurrent.TimeUnit;

public class Voliate1 {
    volatile boolean flag = true;

    public void test(a){
        System.out.println(Thread.currentThread().getName()+"In process"+flag);
        while(flag){
            // system.out.println (thread.currentThread ().getName()+" executing "+flag); // system.out.println (thread.currentThread ().getName()+" executing "+flag); // Why can't you print
        }
        System.out.println(Thread.currentThread().getName()+"End of execution"+flag);
    }

    public static void main(String[] args) {
        Voliate1 t = new Voliate1();
        new Thread(t::test,"t").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.flag = false; }}Copy the code

Hardware follows the MESI: CACHE consistency protocol. When a CPU manipulates data in the CACHE, if the data is a shared variable, the data is read from the CACHE to a register, modified, and the memory data is updated. When the CACHE LINE is set to invalid, the other CPU reads the data from the memory.

Disallow instruction reordering

1. Instructions can be executed concurrently to improve execution efficiency.

2. Singleton mode

lazy

Thread unsafe:

package com.anzhi.voliate;

import org.omg.CORBA.TIMEOUT;

import java.util.concurrent.TimeUnit;

public class SingleModel2 {
    private static SingleModel2 singleModel;
    // Make the constructor private and forbid instantiation
    private SingleModel2(a){};

    // The method to get the object
    public static synchronized SingleModel2 getSingleModel(a){
        if(singleModel == null) {SingleModel is null when accessed by the second thread, which means that two objects are created and synchronized are synchronized
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            singleModel = new SingleModel2();
        }
        return singleModel;
    }

    public static void main(String[] args) {
        new Thread(()->{
            for(int i=0; i<100000; i++) {
                System.out.println(Thread.currentThread().getName() + "-" + SingleModel.getSingleModel().hashCode());
            }
        }).start();

        for(int i=0; i<100000; i++) { System.out.println(SingleModel.getSingleModel().hashCode()); }}}Copy the code

Double check: Ensure thread safety

package cn.yqh.interview;
public class Singleton {

    private static volatile Singleton singleton = null;

    private Singleton(a) {}public static Singleton getInstance(a){
        // First check whether singleton is empty
        if(singleton==null) {synchronized (Singleton.class){
                When thread A determines whether singleton is null for the first time, singleton==null is null. When thread A is about to create an object, the resource is preempted by thread B and synchronized locks. When thread B is finished creating, A will not judge again and directly creates the object, causing the object to be created again.
                if(singleton==null){
                    singleton = newSingleton(); }}}return singleton;
    }


    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {
                public void run(a) {
                    System.out.println(Thread.currentThread().getName()+":"+Singleton.getInstance().hashCode()); } }).start(); }}}Copy the code

Whether to volatile

This involves reordering orders

Analyze the process of applying space for objects:

Create space for the object and assign the initial value a=0; Alter object assignment a=8; A =8; If there is no volatile modifier, then 2,3 if an instruction rearrangement occurs, then 3 and then 2, then a will end up at 0, resulting in data inconsistency. With volatile prohibiting instruction reordering, this does not happen.Copy the code

The hungry

public class SingleModel {
      private static SingleModel singleModel = new SingleModel();
      // Make the constructor private and forbid instantiation
      private SingleModel(a){};

      // The method to get the object
      public static SingleModel getSingleModel(a){
          return  singleModel;
      }

      public static void main(String[] args) { SingleModel ins = SingleModel.getSingleModel(); SingleModel ins2 = SingleModel.getSingleModel(); System.out.println(ins == ins2); }}Copy the code

3. Summary:

1. Volatile: guarantees visibility only, prohibits instruction rearrangement, does not guarantee atomicity, synchronized guarantees atomicity

package com.anzhi.voliate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class Voliate2 {
    Integer count = 0;

    public void test(a){
        for(int i=0; i<10000; i++) count++;
    }

    public static /*synchronized*/  void main(String[] args) {
        Voliate2 t = new Voliate2();

        List<Thread> list = new ArrayList<>();
        for(int i=0; i<10; i++){
            list.add(new Thread(t::test, "t-"+i));
        }

        for (Thread thread : list) {
            thread.start();
        }

        for(Thread thread : list){
            try {
                thread.join();
            } catch(InterruptedException e) { e.printStackTrace(); } } System.out.println(t.count); }}Copy the code

2. Changes in the lock object do not affect the use of the lock

public class Synchronized4 {
private final Object o = new Object();  // Ensure that the lock object is unique

public void test(a){
    synchronized (o){
        while(true) {try {
                TimeUnit.MICROSECONDS.sleep(1);
            } catch(InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); }}}public static void main(String[] args) {
    Synchronized4 o = new Synchronized4();
    for(int i=0; i<10; i++){
        new Thread(()->{
            o.test();
        }).start();
    }

    /* o.o = new Synchronized4(); o.test(); * /
}
Copy the code