当前位置:网站首页>JUC personal simple notes

JUC personal simple notes

2022-06-24 08:31:00 Independent fence window

JUC

Java JUC brief introduction

【JUC Is the abbreviation of the following three packages 】

  • java.util.concurrent
  • java.util.concurrent.atomic
  • java.util.concurrent.locks

【 It means 】 Added in this package Concurrent programming ** In the common The utility class of , Used to define a thread - like self - defined child System , Include Thread pool 、 asynchronous IO And lightweight mission framework . Provide adjustable 、 Flexible thread pool **. Also provided are designs for In a multithreaded context Collection To achieve, etc .

Let's review the previous knowledge of threads .

One 、 The difference between concurrency and parallelism

java Can you really start the thread ?

You can't ,Thread.start() What is called is a local method , The bottom layer of this method is C++

private native void start0();

Concurrent : Multiple threads operate on a resource ( Alternate execution

  • CPU A nucleus , Simulate multiple threads
  • The essence : make the best of CPU Resources for , All companies value it

** parallel :** Multiple threads executing at the same time ( At the same time

  • CPU Multicore , Multiple threads executing at the same time
  • You can use thread pools to improve performance

Get the computer's audit through the code :

public class demo1 {
    
    public static void main(String[] args) {
    
        // Get a computer CPU Check the number 
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

Six states of thread : Thread.State

 public enum State {
    
        /** *  newly build  */
        NEW,

        /** *  function  */
        RUNNABLE,

        /** *  Blocking  */
        BLOCKED,

        /** *  wait for , Dead, etc  */
        WAITING,

        /** * Overtime waiting , When time passes, it doesn't wait  */
        TIMED_WAITING,

        /** *  end  */
        TERMINATED;
    }

Two 、wait And sleep difference

【 It means 】 Is to let the thread sleep

【 notes 】 Calling these two methods usually uses a JUC Tools in TimeUnit ,TimeUnit Is an enumeration class , When you can set 、 branch 、 second 、 Microsecond 、 Days sleep time .TimeUnit.SECONDS.wait(100): It's sleep 100 second

1、 From different packages

TimeUnit.SECONDS.wait(): java.lang.Object

TimeUnit.SECONDS.sleep(): java.util.concurrent

2、 The release of the lock is different

wait: Can release the lock , Leave it to the system management

sleep: It won't release the lock , It's like sleeping with a lock . Thread control will not be handed over after hibernation ,” It's not shit to occupy the manger “.

3、 The scope of use is different

wait: The code block must be resynchronized using

sleep: It can be used anywhere


3、 ... and 、Lock lock

【 It means 】 Lock It's an interface , The bag it's in is java.util.concurrent.locks

Lock Lock and Synchronized difference

Synchronized Is the key word .Lock Is a class

Synchronized Unable to determine the status of the acquired lock .Lock It can be judged whether the lock is obtained

Synchronized Will automatically release the lock . Lock The lock must be released manually , Otherwise, deadlock will occur .

Synchronized When a thread 1 Get lock into blocking state , Threads 2 Will be waiting .Lock Not always waiting for

Synchronized Reentrant lock , It is impossible to interrupt , Not fair lock .Lock Interrupts , Fair lock and unfair lock can be set

Synchronized Suitable for locking a small number of code synchronization problems .Lock Locks are suitable for a large number of synchronized code .

Lock Implementation class of interface

1. Reentrant lock :ReentrantLock class Commonly used

【 It means 】 Reentrant means that a thread has acquired a lock , After entering the thread, the method will automatically acquire the lock if it encounters another lock ( If the lock object is the same object , The thread is the same thread ), The lock can be acquired again without deadlock , establish lock object

【 Construction method 】 ReentrantLock Implementation classes have two constructors , They are Fair and non-fair locks

Fair lock : seeing the name of a thing one thinks of its function , first come , first served , The subsequent thread must wait for the previous thread to execute before entering .

Not fair lock : You can jump in line ,java By default, unfair locks are used .

【 Why use unfair locks by default ?】

Such as :

 One thread execution 3 Get the lock first , Another thread executes 3 Seconds later , If a fair lock is used   perform 3 Second thread   Wait for this  3 Hours before the thread is executed .

 And because the unfair lock can jump the queue , You can make this 3 The second thread executes first , This is why unfair locks are used by default ,Synchronized The same is true of synchronous locks .
// Not fair lock  
	public ReentrantLock() {
    
        sync = new NonfairSync();
    }
// Fair lock 
	public ReentrantLock(boolean fair) {
    
        sync = fair ? new FairSync() : new NonfairSync();
    }

2、 Read-write lock

official

  • A ReadWriteLock Maintain a pair of related locks , One for read-only operations , One for writing . read lock It can be done by multiple reader threads at the same time , As long as there is no author . write lock It's exclusive

It means 】 Shared locks and exclusive locks are also called read-write locks , Shared locks allow multiple threads to read data at the same time , An exclusive lock can only be written by one thread .

ReadWriteLock lock = new ReentrantReadWriteLock();
   lock.writeLock().lock(); // Write lock  lock.writeLock().unlock();// Release 
   lock.readLock().lock();// Read the lock   lock.readLock().unlock();// Release 

Code

package com.readwritelock;

import org.omg.PortableServer.THREAD_POLICY_ID;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {
    
    public static void main(String[] args) {
    
        test2 test1 = new test2();

        for (int i = 0; i < 6; i++) {
    
            final int a = i;
           new Thread(()->{
    test1.set(a+"a",a+"");},String.valueOf(i)).start();
        }


        for (int i = 0; i < 6; i++) {
    
            final int a = i;
            new Thread(()->{
    test1.get(a+"a");},String.valueOf(i)).start();
        }
    }
}
class  test2 {
    
    // Read-write lock 
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    private Map<String, Object> map = new HashMap<>();

    // Write lock 
    public void set(String key, Object value) {
    
        lock.writeLock().lock(); // locked 
        try {
    
            System.out.println(Thread.currentThread().getName() + " Write in ");
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + " Write successfully ");
        } catch (Exception e) {
    
            e.printStackTrace();
        } finally {
    
            lock.writeLock().unlock();// Release 
        }
    }

    // Read the lock 
    public void get(String key) {
    
        lock.readLock().lock();// locked 
        try {
    
            System.out.println(Thread.currentThread().getName() + " Reading ");
            map.get(key);
            System.out.println(Thread.currentThread().getName() + " Read successful ");
        } catch (Exception e) {
    
            e.printStackTrace();
        } finally {
    
            lock.readLock().unlock();// Release 
        }
    }
}
    // Custom cache , No read / write lock 
class Test1 {
    
        private Map<String, Object> map = new HashMap<>();

        public void set(String key, Object value) {
    
            System.out.println(Thread.currentThread().getName() + " Write in ");
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + " Write successfully ");
        }

        public Object get(String key) {
    
            System.out.println(Thread.currentThread().getName() + " Read successful " + map.get(key));
            return map.get(key);
        }
    }


What is a lock , How to judge who the lock is ?

Four 、 producers and consumers

What is producer to consumer ( It's reading and writing )?

The main role of the producer is to generate a certain amount of data and put it in the buffer , Then repeat the process . meanwhile , Consumers are also consuming this data in the buffer . The key to this problem is to ensure that producers do not add data when the buffer is full , Consumers also don't consume data when the buffer is empty .

There are communication problems between threads : Then the interviewer will ask you about the producers and consumers

1、 Old version ( Synchronized) The producers and consumers of

The method of communication between threads Synchronized Of wait(); Waiting to wake up ,notify(); Notification wake up

【 Code 】:

Multiple thread operations num = 0; Add and subtract

【 problem 】 When only A、B Threads are perfect for synchronous operations , But when it appears C、D There will be asynchronous operations after the thread .

Why the following code is out of sync ?

package com;

public class demo3 {
    
    public static void main(String[] args) {
    
        A a = new A();
        new Thread(() -> {
    
            // producer 
            try {
    
                for (int i = 0; i < 10; i++) a.increment();
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }, "A").start();
        new Thread(() -> {
    
            // consumer 
            try {
    
                for (int i = 0; i < 10; i++)
                    a.deccrement();
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }, "B").start();
        
        /*  Yes C、D Out of sync after thread  */
        new Thread(() -> {
    
			// consumer 
            try {
    
                for (int i = 0; i < 10; i++)
                      a.deccrement();
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }, "C").start();

        new Thread(() -> {
    
           // producer 
            try {
    
                for (int i = 0; i < 10; i++)
                    
                 a.increment();
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }, "D").start();

    }
}

// The pithy formula of producers and consumers : Judge wait 、 Business 、 notice 
class A {
    
    private int num = 0;

    public synchronized void increment() throws InterruptedException {
    
        if (num != 0) {
    
            this.wait();// Waiting to wake up 
        }
        num++;
        System.out.println(Thread.currentThread().getName() + "=>" + num);
        // Notify other threads ,+1 complete 
        this.notifyAll();// Wake up other threads 
    }

    public synchronized void deccrement() throws InterruptedException {
    
        if (num == 0) {
    
            this.wait(); // Waiting to wake up 
        }
        num--;
        System.out.println(Thread.currentThread().getName() + "=>" + num);
        // Notify other threads ,-1 complete 
        this.notifyAll();// Wake up other threads 
    }
}

Out of sync flowchart :

image-20200220141201705

Why is there asynchrony ?

This problem is also called spurious wakeup The reason is that waiting for wakeup is to use if Judge ,if Only one judgment will be made , When two threads enter at the same time +1 Method , It may only be done once .

and jdk Documentation is for us to use while:

Like in a parametric version , Interruptions and false awakenings are possible , And this method should always be used in the loop :

  synchronized (obj) {
    
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     } 

So prevent false awakening , We just need to if Change to while Just judge , Why? while And then we can solve this problem ?

because while It will not stop after making a judgment , Will continue to judge . and if It's over after only one judgment .

2、JUC Producers and consumers of version

【 It means 】 Lock Can replace Synchronize Classes and methods wait(),notifyAll().

【 Use 】

ReentrantLock(): Lock Implementation class of interface ReentrantLock(); Reentrant lock .

 Lock lock = new ReentrantLock(); // Create a reentrant lock object 

establish Condition() object , Call instead of waiting for wakeup , And notification wake-up method .

**await :** Instead of wait()

**signalAll :** Instead of notifyAll()

Condition condition = lock.newCondition();

Before the change Synchronized Sample code

class B {
    
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    private int num = 0;

    public  void increment() throws InterruptedException {
    
        lock.lock();
        try {
    
            while (num != 0) {
    
                condition.await();
            }
            num++;
            System.out.println(Thread.currentThread().getName() + "=>" + num);
            condition.signalAll();
        } catch (InterruptedException e) {
    
            e.printStackTrace();
        } finally {
    
            lock.tryLock();
        }
    }

    public  void deccrement() throws InterruptedException {
    
        lock.lock();
        try {
    
            while (num == 0) {
    
               condition.await(); // wait for 
            }
            num--;
            System.out.println(Thread.currentThread().getName() + "=>" + num);
            // Notify other threads ,-1 complete 
            condition.signalAll();
        } catch (InterruptedException e) {
    
            e.printStackTrace();
        } finally {
    
            lock.tryLock();
        }

    }
}

【 It means 】 Use Lock Operation results and Synchronized The result is the same .

【 notes 】 The emergence of a new technology does not just cover the previous technology , If so, it is not necessary to use Lock 了 .Lock Can achieve Synchronized Impossible Precise awakening .

3、Lock Precise awakening

【 It means 】 Accurately wake up the corresponding thread , That is, execute threads in the order you need them , such as A Threads —> B Threads —> C Threads

【 Implementation code 】

package com;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Lock2 {
    
    public static void main(String[] args) {
    
        C a = new C();
        new Thread(() -> {
    
            try {
    
                for (int i = 0; i < 10; i++)
                    a.a();
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }, "A").start();
        new Thread(() -> {
    
            try {
    
                for (int i = 0; i < 10; i++)
                    a.b();
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }, "B").start();

        new Thread(() -> {
    
            try {
    
                for (int i = 0; i < 10; i++)
                    a.c();
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }, "C").start();

    }
}

// formula : Judge wait 、 Business 、 notice 
class C {
    
    Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();
    private int num = 1;

    public  void a() throws InterruptedException {
    
        lock.lock();
        try {
    
            while (num != 1) {
    
                condition1.await();
            }
            num = 2;
            System.out.println(Thread.currentThread().getName() + "=> AAAAAAAAAA" );
            condition2.signal();
        } catch (InterruptedException e) {
    
            e.printStackTrace();
        } finally {
    
            lock.tryLock();
        }
    }

    public  void b() throws InterruptedException {
    
        lock.lock();
        try {
    
            while (num != 2) {
    
               condition2.await(); // wait for 
            }
            num = 3;
            System.out.println(Thread.currentThread().getName() + "=> BBBBBBBBBB");
            // Notify other threads ,-1 complete 
            condition3.signal();
        } catch (InterruptedException e) {
    
            e.printStackTrace();
        } finally {
    
            lock.tryLock();
        }
    }
    public  void c() throws InterruptedException {
    
        lock.lock();
        try {
    
            while (num != 3) {
    
                condition3.await(); // wait for 
            }
            num = 1;
            System.out.println(Thread.currentThread().getName() + "=>CCCCCC");
            // Notify other threads ,-1 complete 
            condition1.signal();
        } catch (InterruptedException e) {
    
            e.printStackTrace();
        } finally {
    
            lock.tryLock();
        }
    }
}

5、 ... and 、 Eight lock phenomenon

【 notes 】

1、Synchronized The lock is the caller , The locking of two object callers does not affect each other .

2、static Synchronized Locked Class, It's a template . There is only one class Class.

3、 If a caller calls static Synchronized Lock another call Synchronized lock , Because the concepts of these two locks are different , Not the same lock , So the locking of the two callers does not affect each other . Therefore, the synchronization operation will not be performed .

6、 ... and 、Callable< V >

【JDK documentation 】

Callable The interface is similar to Runnable, Because they are designed for classes whose instances may be executed by another thread . However , Runnable No results returned , You can't throw checked exceptions .

It means 】 You can have a return value , You can throw an exception .

Method

**V call() :** The return value must be the same as the collection type of the interface .

because Thread Only with Runnable Interface related ,Callable Not directly related to Thread, So we need a middleman .

FurureTask Realized Runnable Interface ,FurureTask There are two parametric constructions of , A reference is Runnable, Another reference is Callable.

Code

package com.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Callabletest {
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        Helloworld helloworld = new Helloworld();

        FutureTask futureTask = new FutureTask(helloworld); // call Callable structure 

        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start();
        String o = (String) futureTask.get();// get Callable Return value ,get There will be obstruction. , Usually put the last line , Get asynchronous operation .
        System.out.println(o);
    }
}

class Helloworld implements Callable<String> {
     // Realization Claable Interface 
    public String call(){
     // The return value must be the same as the generic type of the interface .
        System.out.println(" Hey ");
        return " Hello ";
    }
}

7、 ... and 、 Common auxiliary classes

1、CountDownLatch Subtraction counter

It means 】 Synchronization assist that allows one or more threads to wait until a set of operations performed in other threads complete

Method

    • Modifier and TypeMethod and Description
      void****await() Counter to 0 After being awakened , Allow execution to proceed .
      booleanawait(long timeout, TimeUnit unit) Causes the current thread to wait until the latch count reaches zero , Unless the thread is interrupted Or the specified waiting time has passed .
      voidcountDown() Reduce the latch count , If the count reaches zero , Release all waiting threads .
      longgetCount() Returns the current count .
      StringtoString() Returns a string identifying the latch and its status .

Code

package com.callable;

import java.util.concurrent.CountDownLatch;

public class CountDownLathTest {
    
    public static void main(String[] args) throws InterruptedException {
    
        CountDownLatch cdl = new CountDownLatch(6);
        for (int i = 1; i <= 6; i++) {
    

            new Thread(()->{
    
                System.out.println(Thread.currentThread().getName()+" get out ");
                cdl.countDown(); // Every reduction 1
            },String.valueOf(i)).start();

        }
        cdl.await();// After all, continue to run , Otherwise blocking 
        System.out.println(" It's all done !");
    }
}

2、 CyclicBarrier Add counter

It means 】 It's similar to subtraction , One is plus and one is minus

Method

    • Modifier and TypeMethod and Description
      intawait() Wait for all parties Has been invoked on this barrier await .
      intawait(long timeout, TimeUnit unit) Wait for all parties Has been called on this barrier await , Or the specified waiting time has passed .
      intgetNumberWaiting() Return to the number of parties currently waiting for obstacles .
      intgetParties() The number of parties required to return to the obstacle of travel .
      booleanisBroken() Check whether the obstacle is broken .
      voidreset() Reset the barrier to its initial state .

Code

package com.callable;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    
    public static void main(String[] args) {
    
        CyclicBarrier barrier = new CyclicBarrier(5,()->{
    
            System.out.println(" Achieve the operation objective ");
        });
        for (int i = 0; i < 5; i++) {
    
           new Thread(()->{
    
               System.out.println(Thread.currentThread().getName()+" function ");
               try {
    
                   barrier.await();// When the running thread reaches 5 when , function lambda expression 
               } catch (InterruptedException e) {
    
                   e.printStackTrace();
               } catch (BrokenBarrierException e) {
    
                   e.printStackTrace();
               }
           },String.valueOf(i)).start();
        }
    }
}

3、Semaphore Semaphore

It means 】 Set the maximum number of threads , Mutually exclusive use of multiple shared resources ! Concurrent current limiting , Control the number of threads !

Code

package com.callable;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.jar.Manifest;

public class SemaphoreTest {
    
    public static void main(String[] args) {
    
        // Number of threads : Parking space  3 ! It is often used in current limiting 
        Semaphore semaphore = new Semaphore(3);
        for (int i = 1; i <= 6; i++) {
    
            final int a = i;
            new Thread(()->{
    
                try {
    
                    semaphore.acquire();// Get a parking space 
                    System.out.println(a+" Come in on the th ");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(a+" Go out on the th ");
                } catch (InterruptedException e) {
    
                    e.printStackTrace();
                }finally {
    
                    semaphore.release();// Release the parking space 
                }
            },String.valueOf(i)).start();
        }
    }
}

principle :

semaphore.acquire() : get , Assume thread is full , Other threads will wait , Until they are released

semaphore.release(): Release , Release the current semaphore +1, Then wake up the waiting thread .

8、 ... and 、 Thread unsafe

package com.collections;

import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.CopyOnWriteArrayList;

public class demo1 {
    
// java.util.ConcurrentModificationException  Concurrent modification exception 
    public static void main(String[] args) {
    
// List list = new ArrayList();  It is not safe to read and write collections concurrently 
/*  terms of settlement : 1、List list = new Vector(); Vector Of add() Method used synchronized Synchronization lock  2、List list = Collections.synchronizedList(new ArrayList<>()); 3、List list = new CopyOnWriteArrayList();  Copy on write  */
        Set set = new ConcurrentSkipListSet();
        for (int i = 0; i < 100; i++) {
    
            new Thread(()->{
    
               set.add(UUID.randomUUID().toString().substring(5));
                System.out.println(set);
            },String.valueOf(i)).start();

        }

    }


}

Nine 、 Blocking queues

background

Blocking queues (BlockingQueue) Is a queue that supports two additional operations . These two additional operations support blocking insert and remove methods

1) Supports blocking insertion methods : It means when the queue is full , The queue blocks the thread that inserts the element , Until the line is not satisfied .

2) Support blocking removal methods : It means when the queue is empty , The thread that gets the element will wait for the queue to become non empty

Blocking queues are often used in producer and consumer scenarios , The producer is the thread that adds elements to the queue , The consumer is the thread that fetches elements from the queue . Blocking queues are used by producers to store elements 、 The container consumers use to get elements .

It means

FIFO First in, first out

There is a passage , The left slot is for writing data , On the right is reading data , If no data is read on the right , This channel will always be written , When the passage is full, it will be blocked and waiting . conversely When the data of this channel is zero , Reading data is unreadable , Also block . Must wait for this channel to have data .

** Write :** If the queue is full , You have to wait .

** read :** If the queue is empty , Must be blocked waiting for production .

It's not new ,BlockingQueue Inherit Queue =>Queue Inherit Collection

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-KV2Agitv-1655823180745)(C:\Users\ Single column window \AppData\Roaming\Typora\typora-user-images\image-20200225164513667.png)]

Implement blocking queue

The way Throw an exception There is a return value , Don't throw exceptions Block waiting Overtime waiting
add to boolean add(E e)boolean offer(E e)void put(E e)offer(E,Long,TimeUnit)
Output T remove()T poll()T take()poll(Long,TimeUnit)
Check the first element element()

Throw an exception :

// It throws an exception 
class Test1{
    
    public void test(){
    
        ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3);

        System.out.println(arrayBlockingQueue.add("a"));
        System.out.println(arrayBlockingQueue.add("b"));
        System.out.println(arrayBlockingQueue.add("c"));
        // When the line is full , Add the throw   abnormal  IllegalStateException: Queue full  The queue is full 
// System.out.println(arrayBlockingQueue.add("c"));

        System.out.println(arrayBlockingQueue.remove());
         System.out.println(arrayBlockingQueue.remove());
        System.out.println(arrayBlockingQueue.remove());
        
        // If there is no first element , Throw out :java.util.NoSuchElementException  There is no such element 
        System.out.println(arrayBlockingQueue.element());
//  There is no data for the column , Throw out :java.util.NoSuchElementException
// System.out.println(arrayBlockingQueue.remove());

    }
}

Don't throw exceptions :

// Don't throw exceptions 
class Test2{
    
    public void test(){
    
        LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue(3);

        System.out.println(linkedBlockingQueue.offer("a"));
        System.out.println(linkedBlockingQueue.offer("b"));
        System.out.println(linkedBlockingQueue.offer("c"));
        // When the line is full , return flase
// System.out.println(linkedBlockingQueue.offer("d"));

        System.out.println(linkedBlockingQueue.poll());
        System.out.println(linkedBlockingQueue.poll());
        System.out.println(linkedBlockingQueue.poll());
        // If there is no first element , Output empty 
// System.out.println(linkedBlockingQueue.poll());
 }

}

Block waiting :

// Block waiting 
class Test3{
    
    public void test() throws InterruptedException {
    
        LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue(3);
        linkedBlockingQueue.put("a");
        linkedBlockingQueue.put("c");
        linkedBlockingQueue.put("b");
        // When the line is full , Enter the block and wait 
// linkedBlockingQueue.put("c");
        System.out.println(linkedBlockingQueue.take());
        System.out.println(linkedBlockingQueue.take());
        System.out.println(linkedBlockingQueue.take());
        // If there is no first element , Enter the block and wait 
// System.out.println(linkedBlockingQueue.takce());
    }
}

Overtime waiting :

// Overtime waiting 
class Test4{
    
    public void test() throws InterruptedException {
    
        LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue(3);
        System.out.println(linkedBlockingQueue.offer("a" ));
        System.out.println(linkedBlockingQueue.offer("c" ));
        System.out.println(linkedBlockingQueue.offer("c"));
        // When the line is full , Enter timeout wait , wait for 2 second , Leave without a place 
        System.out.println(linkedBlockingQueue.offer("c", 2, TimeUnit.SECONDS));

        System.out.println(linkedBlockingQueue.poll());
        System.out.println(linkedBlockingQueue.poll());
        System.out.println(linkedBlockingQueue.poll());
        // When the queue is empty , Enter timeout wait , wait for 2 second , Leave without data 
        System.out.println(linkedBlockingQueue.poll(2,TimeUnit.SECONDS));
    }
}
SynchronousQueue Synchronous queue

It means 】 No capacity , Only one element can be placed , We have to wait for this element to come out , To put down an element .

// Synchronous queue 
class Test5{
    
    public void test() throws InterruptedException {
    
        SynchronousQueue synchronousQueue = new SynchronousQueue();
        new Thread(()->{
    
            try {
    
                System.out.println(Thread.currentThread().getName()+"1");
                synchronousQueue.put("1");
                System.out.println(Thread.currentThread().getName()+"2");
                synchronousQueue.put("2");
                System.out.println(Thread.currentThread().getName()+"3");
                synchronousQueue.put("3");
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        },"A").start();

        new Thread(()->{
    
            try {
    
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+synchronousQueue.poll());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+synchronousQueue.poll());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+synchronousQueue.poll());
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }

        },"B").start();
    }
}

Ten 、 Thread pool

** remember :** Three ways 、 Seven parameters 、 Four rejection strategies

【 background 】

If the program has a large number of short-time threaded tasks , Because creating and destroying threads need to interact with the underlying operating system , A lot of time is spent creating and consuming threads , So it is a waste of time , Low efficiency .

After each thread task in the thread pool is completed , It's not going to die , Instead, go back to the thread pool and become idle again , Wait for the next object to use , Therefore, with the help of thread pool, the execution efficiency of the program can be improved

advantage

1、 Improve the response speed of the program , Reduce resource consumption

2、 Control the number of threads , Prevent the program from crashing

3、 Easy to manage .

4、 Thread reuse 、 You can control the maximum number of concurrent 、 Manage threads

1、 Create thread of : Three ways

【 Alibaba development manual stipulates 】

【 mandatory 】 Thread resources must be provided through the thread pool , It is not allowed to explicitly create threads in the application . explain : The advantage of using thread pool is to reduce the time spent on creating and destroying threads and the overhead of system resources , Settlement fund
The problem of insufficient sources . If you do not use thread pools , It may cause the system to create a large number of similar threads, leading to memory consumption or “ Over switching ” The problem of .

【 mandatory 】 Thread pools are not allowed Executors To create , But through ThreadPoolExecutor The way , such To make the rules of the thread pool more explicit , Avoid the risk of resource depletion . explain :Executors The disadvantages of the returned thread pool object are as follows :
1)FixedThreadPool and SingleThreadPool: The allowed request queue length is Integer.MAX_VALUE, A large number of requests may pile up , Which leads to OOM.

2)CachedThreadPool and ScheduledThreadPool: The number of threads allowed to be created is Integer.MAX_VALUE, A large number of threads may be created , Which leads to OOM.

Integer.MAX_VALUE = Maximum 21 Billion

**OOM **: Out of memory recommend :https://blog.csdn.net/qq_42447950/article/details/81435080

Three ways

// Alibaba does not recommend the following three methods 
public class Demo1 {
    
    public static void main(String[] args) {
    
// ExecutorService executorService = Executors.newSingleThreadExecutor();// Single thread pool   Maximum number of threads executed together 1 strip 
// ExecutorService executorService =Executors.newFixedThreadPool(5); // Fixed thread pool   Maximum number of threads executed together 5 strip 
         ExecutorService executorService = Executors.newCachedThreadPool(); // Scalable threads   Scale by number of threads executing 

        try {
    
            for (int i = 0; i < 10; i++) {
    
                executorService.execute(()->{
    
                    System.out.println(Thread.currentThread().getName()+"ok");
                });
            }
        } catch (Exception e) {
    
            e.printStackTrace();
        } finally {
    
            executorService.shutdown();
        }
    }
}

2、 Seven parameters

Source code analysis

The above three methods that Alibaba does not recommend are all called ThreadPoolExecutor Construction method of .

So we need to realize it ourselves ThreadPoolExecutor Define thread pool , because ThreadPoolExecutor Is safe .

    public ThreadPoolExecutor(int corePoolSize, // Thread size reserved when idle 
                              int maximumPoolSize,// Maximum number of startup threads 
                              long keepAliveTime, //  If no one calls after the timeout, it will be released  
                              TimeUnit unit,//  Time out unit 
                              BlockingQueue<Runnable> workQueue, // Blocking queues 
                              ThreadFactory threadFactory, // Create a thread factory , It doesn't change 
                              RejectedExecutionHandler handler // Refusal strategy 
                              ) {
    
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

call ThreadPoolExecutor

Customize ThreadPoolExecutor

package com.pool;

import java.util.concurrent.*;
// Executors  Tool class 、3 The big way 

// Executors  Tool class 、3 The big way 

/**  Refusal strategy  * new ThreadPoolExecutor.AbortPolicy() //  The bank is full , There are people coming in , Don't deal with this person's , Throw an exception  * new ThreadPoolExecutor.CallerRunsPolicy() //  Where they come from, where they go ! * new ThreadPoolExecutor.DiscardPolicy() // The queue is full , Lose the job , Does not throw an exception ! * new ThreadPoolExecutor.DiscardOldestPolicy() // The queue is full , Try to compete with the early , Not even   Throw an exception ! */
public class Demo2 {
    
    public static void main(String[] args) {
    
        // Custom thread pool !  Use ThreadPoolExecutor  actuator 
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                2,
                Runtime.getRuntime().availableProcessors(),
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        // The maximum number of threads in this thread pool :Deque + max = 8
        // More than will throw  RejectedExecutionException
        // Exception handling block   Ensure that the loop ends normally before closing the thread 
        try {
    
            for (int i = 0; i < 9; i++) {
    
                threadPoolExecutor.execute(() -> {
    
                    System.out.println(Thread.currentThread().getName() + " ok");
                });
            }
        } catch (Exception e) {
    
            e.printStackTrace();
        } finally {
    
            threadPoolExecutor.shutdown();
        }
    }
}

3、 Four rejection strategies

/** * new ThreadPoolExecutor.AbortPolicy() //  The bank is full , There are people coming in , Don't deal with this person's , Throw an exception  * new ThreadPoolExecutor.CallerRunsPolicy() //  Where they come from, where they go ! * new ThreadPoolExecutor.DiscardPolicy() // The queue is full , Lose the job , Does not throw an exception ! * new ThreadPoolExecutor.DiscardOldestPolicy() // The queue is full , Try to compete with the early , Not even   Throw an exception ! */

11、 ... and 、 Four functional interfaces

New era program writing code :lambda 、 Linked list 、 Functional interface 、Stream Flow computation

@FunctionalInterface 
public interface Runnable {
     
    public abstract void run(); 
}
//  Generic 、 enumeration 、 Reflection  
// lambda expression 、 Chain programming 、 Functional interface 、Stream Flow computation 
//  Super many FunctionalInterface //  Simplify the programming model , It is widely used at the bottom of the new version of the framework !
// foreach( The functional interface of the consumer class )

It means 】 The interface with only one method is the functional interface , The following red lines are the four functional interfaces , The rest are derived from the four function interfaces , Common in many frameworks .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-2JpXvfU1-1655823180747)(C:\Users\ Single column window \AppData\Roaming\Typora\typora-user-images\image-20200226205310489.png)]

1、 Consumer interface (Consumer)

It means 】 Input only, no output , That is, only parameters , no return value .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-w9dcgY5c-1655823180749)(C:\Users\ Single column window \AppData\Roaming\Typora\typora-user-images\image-20200226211604297.png)]

package com.function;

import java.util.function.Consumer;

/** * Consumer  Consumer interface  * (str)->{ System.out.println(str); };  Equal to the implementation class  * consumer.accept(s);  Call the output method above  */
public class ConsumerTest {
    
    public static void main(String[] args) {
    
        String s = " How do you do ";
        Consumer<String> consumer  = (str)->{
     System.out.println(str); }; // Create objects 
        consumer.accept(s);
    }
}

2、 Functional interface (Function)

It means 】 There is an input , There is a return value

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-bsxvQarU-1655823180749)(C:\Users\ Single column window \AppData\Roaming\Typora\typora-user-images\image-20200226213602740.png)]

package com.function;

import java.util.function.Function;

public class FuncationTest {
    
    public static void main(String[] args) {
    
        // Parameter must be String, The return value must be Integer
        Function<String,Integer> function = (str)->{
    
            System.out.println(" Input :"+str);
            return 123;
        };

        System.out.println(" return :"+function.apply("321"));

    }
}

3、 Assertive interface (Predicate)

It means 】 There is an input parameter 、 The return value can only be boolean value

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-BvNy7Sdo-1655823180750)(C:\Users\ Single column window \AppData\Roaming\Typora\typora-user-images\image-20200226212359215.png)]

package com.function;

import java.util.function.Predicate;

public class PredicateTest {
    
    public static void main(String[] args) {
    
        Integer i = 0;
        Predicate<Integer> predicate = (a)->{
    return a==0;};
        System.out.println(predicate.test(i)); // return true
    }
}

4、 Supply type interface (Supplier)

It means 】 No parameters , Only the return value

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-ZdK9vbKB-1655823180750)(C:\Users\ Single column window \AppData\Roaming\Typora\typora-user-images\image-20200226214300504.png)]

package com.function;

import java.util.function.Supplier;

public class SupplierTest {
    
    public static void main(String[] args) {
    
        Supplier<String> supplier = ()->{
    return "123";}; // The output must be String
        System.out.println(" Output :"+supplier.get());
    }
}

Twelve 、Stream Flow computation

What is? Stream Flow computation ?

The essence of big data is storage and computing , Image set 、 A database is storing data , The computation should be left to the flow to operate .

Stream It's the data channel , Used to manipulate data sources ( aggregate 、 Array etc. ) The generated sequence of elements . Collections are about data , Flow is about computation .

Stream API(java.util.stream.*) Stream yes JAVA8 , which deals with key abstractions of collections , It specifies what you want to do with the collection , You can perform very complex lookups 、 Operations such as filtering and mapping data .

Use Stream API Operates on the collection data , It's kind of like using SQL Perform data query . You can also use StreamAPI Do parallel operations , All in all ,StreamAPI Provides an efficient and easy-to-use way to process data .

notes

1 . Stream You don't store elements by yourself .

2 . Stream The source object does not change . contrary , They will return a new Stream

3 . Stream The operation is delayed . This means that they wait until they need results to execute .

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-tSMmMgQS-1655823180751)(C:\Users\ Single column window \AppData\Roaming\Typora\typora-user-images\image-20200226223713869.png)]

package com.stream;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/** *  Subject requirements : Finish the problem in one minute , It can only be implemented in one line of code ! * *  Now there is 5 Users ! Screening : * 1、ID  It must be an even number  * 2、 Age must be greater than 23 year  * 3、 Change user name to uppercase  * 4、 User names are sorted upside down  * 5、 Output only one user ! */
public class StreamTest {
    
    public static void main(String[] args) {
    
        User u1 = new User(1, 23, "a");
        User u2 = new User(2, 24, "b");
        User u3 = new User(3, 25, "c");
        User u4 = new User(4, 26, "d");
        User u5 = new User(5, 27, "e");
        User u6 = new User(6, 26, "f");
        List<User> list = Arrays.asList(u1,u2,u3,u4,u5,u6); // Only store 

        // The calculation is given to Stream flow  filter Screening 
        list.stream()
                .filter((u)->{
    return u.getId()%2==0;})//1、ID  It must be an even number 
                .filter((u)->{
    return u.getAge()>23;})//2、 Age must be greater than 23 year 
                .map((u)->{
    return u.getName().toUpperCase();})//3、 Change user name to uppercase 
                .sorted((uu1,uu2)->{
    return uu2.compareTo(uu1);})//4、 User names are sorted upside down 
                .limit(1)//5、 Output only one user !
                .forEach(System.out::println);// Output 

    }
}

class User {
    
    private int id;
    private int age;
    private String name;
 	//... Omit encapsulation 
}

13、 ... and 、ForkJoin

What is? ForkJoin?

ForkJoin yes JAVA7 A tool class for parallel execution of tasks ,ForkJoin Also called split connection , You can split a big task into a small one , Final summary .

Split connection

img

Job theft algorithm

Job theft (work-stealing) Algorithm means After the execution of a thread from Others have not been completed In the line of steal Task to carry out .

img

Why work theft is needed ?

If we need to do a bigger task , We can divide this task into several independent sub tasks , To reduce the competition between threads , So I put these subtasks in different queues , And create a separate thread for each queue to perform the tasks in the queue , Threads and queues correspond one by one , such as A The thread is responsible for handling A Tasks in a queue .

Some queue threads have finished executing , It's a waste to leave it empty , So let this thread steal a task from other unexecuted queues to execute .

And at this point they access the same queue , So in order to reduce the competition between stealing task thread and being stolen task thread , We usually use a two terminal queue , The thread of the stolen task always takes the task from the head of the two terminal queue to execute , The thread that steals the task will always take the task from the end of the double end queue to execute .

advantage Make full use of threads for computing , Reduce the competition between threads

shortcoming In some cases there will still be competition , For example, when a queue has executed the last task, it is not finished , Another one comes in after the execution to steal , There will be competition .

Code steps

1、 Create a class that inherits ForkJoinTask Interface The abstract implementation class of

​ ForkJoinTask Represents a parallel 、 Merged tasks .ForkJoinTask Is an abstract class , It has two abstract subclasses :RecursiveAction and RecursiveTask.

RecuresiveAction ( Recursive event ): its compute() Method does not return a value , Methods must be abstract , Represents a task with a return value .

RecuresiveTask ( Recursive tasks ): its compute() Method has a return value , Methods must be abstract , Represents a task with no return value .

2、 Realization compute() Method

/*  Calculation  1  Add to  10_0000_0000 Result  */
public class ForkJoinDemo extends RecursiveTask<Long> {
    

    private Long strat; // Initial value 
    private Long end; // End value 

    private Long temp = 1000L; // critical point 

    public ForkJoinDemo(Long strat, Long end) {
    
        this.strat = strat;
        this.end = end;
    }

    @Override
    protected Long compute() {
    
        if ((end - strat) < temp) {
    
            Long sum = 0L;
            for (Long i = strat; i <= temp; i++) {
    
                sum += i;
            }
            return sum; 
        } else {
    
            Long middle = (strat + end) / 2;
            ForkJoinDemo forkJoinDemo1 = new ForkJoinDemo(strat, middle); // It is divided into sub task calculation  0 ~ 5000
            forkJoinDemo1.fork(); // Split the task , Determines whether the current thread is  ForkJoinPool  Type of thread , If not, it will throw AbstractQueuedSynchronizer$Node
            ForkJoinDemo forkJoinDemo2 = new ForkJoinDemo(middle + 1, end); // It is divided into sub task calculation  5000 ~ 10000
            forkJoinDemo2.fork();// Split the task , Asynchronous computation 
            return forkJoinDemo1.join() + forkJoinDemo2.join();
        }
    }
}

3、 use ForkJoinPool Call the class written by yourself

What is? ForkJoinPool?

​ java Provides ForkJoinPool To support splitting a task into multiple calculations , Recapitulation .

​ ForkJoinPool yes ExecutorService Implementation class of , Therefore, it is a special thread pool

notes 】 You have to use ForkJoinPool Of submit(ForkJoinTask task) perhaps invoke(ForkJoinTask task) To execute the specified ForkJoinTask Mission .

because FockJoinTast Of fork() Method will determine whether it is ForkJoinPool Type of thread .

// call FockJoinDemo
class test {
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        test1();
    }
    // It's calculated in the ordinary way 10_0000_0000 when  12959  millisecond 
    // Use ForkJoin  when 8958 millisecond 
    static void test1() throws ExecutionException, InterruptedException {
    
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = new ForkJoinPool(); // establish  ForkJoinPool
        ForkJoinTask<Long> forkJoinTask = new ForkJoinDemo(0L, 10_0000_0000L); //demo Initialization parameters in 
        ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinTask); // To submit a ForkJoinTask To execute .
        Long sum = submit.get(); // Get the returned value 
        long end = System.currentTimeMillis();
        System.out.println("sum=" + sum + "  Time :" + (end - start));
    }
 }
Most efficient computing ,Stream Parallel flow

It's on it ForkJoin Calculation method of , Compared with the ordinary calculation method, it is indeed much improved , Are not the most efficient , We can also use Stream Parallel flow for calculation

Parallel flow
Parallel flow is to divide a content into several data blocks , And use different threads to divide into multiple data blocks , And use different threads to process the flow of each data block . The way of realization is related to ForkJoin almost
JAVA8 Will be optimized in parallel , It's very easy for us to operate data in parallel .Stream API Can declaratively pass parallel() And sequential() Switch between parallel flow and sequential flow . Actually JAVA8 The bottom layer is to use JAVA7 Newly added Fork/Join frame

    // Use Stream  Parallel flow   Highest efficiency   Time consuming 396
    static void test2() throws ExecutionException, InterruptedException {
    
        long start = System.currentTimeMillis();

        Long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);

        long end = System.currentTimeMillis();
        System.out.println("sum=" + sum + "  Time :" + (end - start));
    }

fourteen 、 Asynchronous callback

​ What is the essence of multithreading to improve performance ? In fact, the serial processing steps are processed in parallel , In fact, the total time has not been shortened . That is to say, it used to be necessary to work alone 10 Hours , And ten people doing the same job need 1 Hours , Thus reducing the processing time . But what if there are priority restrictions on work ? For example, at work : It must be coded before testing , Must be designed before coding , Requirements analysis is required before design , Before analysis …… How to improve the performance in this case ? Or how to make full use of threads in this case ?Future Pattern —— Asynchronous call

Calling class

Use Future Implementation class of CompletableFuture

Future: Indicates a task you wish to perform in the future .Future The original : Modeling the outcome of a future event

CompletableFuture : Express Completed future tasks , intend With this class, future tasks can be completed .

package com.asyn;

import javax.rmi.CORBA.Util;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class CompletableFutureTest {
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        //runAsync()  There are no asynchronous callbacks that return results 
// CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
    
// try {
    
// TimeUnit.SECONDS.sleep(2);
// } catch (InterruptedException e) {
    
// e.printStackTrace();
// }
// System.out.println(" Asynchronous execution complete ");
// });
// System.out.println(" The asynchronous task is asleep 2 second ");
// completableFuture.get(); // Waiting for this task to be completed in the future , And then return the result . It can't be placed in the front, it will block 
//
        //supplyAsync  Supply type asynchronous callback   There is a return value 
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
    
            try {
    
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
            System.out.println(" Complete asynchronous tasks ");
            int i = 10/0;
            return 1024;
        });

        System.out.println(" The asynchronous task is asleep 2 second ");

        System.out.println(completableFuture.whenComplete((t,u)->{
    
            System.out.println("t=>" + t); //  Normal return result 
            System.out.println("u=>" + u); //  error message , No exception is  null
        }).exceptionally(e->{
    
            System.out.println(e.getMessage());
            return 500;
        }).get());

    }

}

15、 ... and 、JMM

What is? JMM?

JMM(Java Memory Model):Java Memory model .

JMM Is a convention or concept , It's something that doesn't exist ,

Personal understanding

JMM The memory model specifies that all variables are stored in main memory .

Each thread has a working memory , Working memory holds the main memory variables used by this thread Copy copy .

All operations on variables ( Read 、 Assignment etc. ) Must be done in working memory , Direct reading of variables in main memory is not allowed .

Different threads cannot directly access each other's working memory , Need to pass with main memory .

When the variable copied by a thread is modified , must Refresh immediately Into main memory . And read the latest value of main memory into working memory .

In order to achieve Cache consistency protocol .

About JMM Some synchronous conventions of :
1、 Before thread unlocking , Shared variables must be immediately Swipe back to main memory .
2、 Before thread locking , The latest value in main memory must be read into working memory !
3、 Lock and unlock are the same lock

Main memory working memory 8 Kind of operation

For these 8 Operation analysis :

But it raises a question :

A Threads don't know flag Variable is B Thread changed . Caused visibility problems .

Code demonstration :

result 】 Use useless declarations volatile Of num,while It's going to keep cycling , because while It doesn't know where the thread is num Be changed to 1 了 .

package com.tvolatile;

import java.util.concurrent.TimeUnit;

public class TestVolatile {
    
    //private static volatile int num = 0; // Guaranteed visibility 
    private static volatile int num = 0;  // Visibility is not guaranteed 
    public static void main(String[] args) {
    
        new Thread(()->{
    
            while (num == 0){
     // Infinite loop 

            }
        }).start();

        try {
    
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
            e.printStackTrace();
        }

        num = 1;
        System.out.println(num);
    }
}

** How to ensure data synchronization ?** have access to Volatile、final or synchronized,Lock.

sixteen 、Volatile

What is? Volatile?

Is a lightweight synchronization keyword .

effect :

1、 Guaranteed visibility

2、 There is no guarantee of atomicity

3、 Prevent command rearrangement .

Guaranteed visibility

It means 】 When a thread changes the value of a shared variable , Other threads will be able to immediately learn about this notification .

There is a bus between main memory and working memory , And the thread will enable sniffing mechanism ( monitoring ) Once the main memory changes, it will copy the data .

Modify the above code , Add to variable volatile keyword , This ensures the visibility of variables ,while No more dead circulation .

Code

package com.tvolatile;

import java.util.concurrent.TimeUnit;

public class TestVolatile {
    
    private volatile static int num = 0;  // Guaranteed visibility 
    public static void main(String[] args) {
    
        new Thread(()->{
    
            while (num == 0){
    

            }
        }).start();

        try {
    
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
            e.printStackTrace();
        }

        num = 1;
        System.out.println(num);
    }
}

There is no guarantee of atomicity

What is atomicity ?

All the data modification operations it has done are performed , Or not at all , Can't be disturbed , It can't be divided .

from Java The atomicity variable operations directly guaranteed by the memory model include read、load、assign、use、store and write. It can be roughly assumed that operations of basic data types are atomic . meanwhile lock and unlock Can guarantee the atomicity of a wider range of operations . and synchronize The atomicity of synchronous block operations is to use higher-level bytecode instructions monitorenter and monitorexit To implicitly operate .

package com.tvolatile;

public class TestVolatile2 {
    
    /** * There is no guarantee of atomicity , The value of each calculation is different , The calculated value should be 30000 */
    private static volatile int num = 0;
    static  void numPlus(){
    
        num++; // num++  It's not atomic , You can decompile it and see 
    }
    public static void main(String[] args) {
    

        for (int i = 0; i < 30; i++) {
    
           new Thread(()->{
    
                for (int j = 0; j < 1000; j++) {
    
                    numPlus();
                }
            }).start();
        }

        while (Thread.activeCount()>2){
     // Why greater than 2, because JAVA There are two threads   One is the main thread , One is GC Threads 
            Thread.yield();
        }
        System.out.println(num);
    }
}

// Output :27597  It's hard to be right anyway :30000

How can we guarantee atomicity ? have access to JUC The type of atom Location package :java.util.concurrent.atomic

Modify the above code :

package com.tvolatile;

import java.util.concurrent.atomic.AtomicInteger;

public class TestVolatile2 {
    
    /** * It ensures both visibility and atomicity , The calculated value is 30000 */
    private volatile static AtomicInteger num = new AtomicInteger(0);
    static  void numPlus(){
    
        num.getAndIncrement(); // Every time +1
    }
    public static void main(String[] args) {
    

        for (int i = 0; i < 30; i++) {
    
           new Thread(()->{
    
                for (int j = 0; j < 1000; j++) {
    
                    numPlus();
                }
            }).start();
        }
        
	// Why should the number of threads be greater than 2, because JAVA There are two threads   One is the main thread , One is GC Threads 
        while (Thread.activeCount()>2){
     
            Thread.yield();
        }
        
        System.out.println(num);
    }
}

Prevent command rearrangement

What is command rearrangement ?

Personal understanding 】 The system will not execute instructions in the order we expect .

such as : Yes A B C D Four properties , As we expect, their execution order should be ABCD ,

But because the system will rearrange instructions , So it may become DCBA perhaps BCDA,CBDA.

Volatile Using the memory barrier prevents this from happening .

Volatile Memory barrier function :

1、 Ensure the execution sequence of specific operations

2、 Memory visibility of some variables can be guaranteed ( Use these features volatile Visibility is achieved )

seventeen 、 Completely play with singleton mode

What is singleton mode ?

Ensure that the class can only have one object in memory , And construct private .

** Main solution :** A globally used class is frequently created and destroyed .

  • 1、 A singleton class can have only one instance .
  • 2、 The singleton class must create its own unique instance .
  • 3、 The singleton class must provide this instance to all other objects .

advantage :

  • 1、 There is only one instance in memory , Reduced memory overhead , In particular, instances are created and destroyed frequently ( For example, cache the homepage of Management College ).
  • 2、 Avoid multiple USES of resources ( Like writing a file ).

** shortcoming :** No interface , Cannot inherit , Conflict with single responsibility principle , A class should only care about internal logic , But I don't care how to instantiate it outside .

Starving model

It means 】 The instance is created when the class is loaded ,

advantage 】 Multithreading security , The instance is initialized as soon as the class is loaded

shortcoming 】 Waste of resources

package com.singleton;

/** *  Starving model  *  The real column is created as soon as the class is loaded  *  The disadvantage is that , There will be a waste of resources  */
public class Hungry {
    
    // Resources are wasted 
    Byte[] byte1 = new Byte[1024];
    Byte[] byte2 = new Byte[1024];
    Byte[] byte3 = new Byte[1024];
    Byte[] byte4 = new Byte[1024];

   private Hungry(){
    

   }

   private static Hungry hungry = new Hungry();

   public static Hungry getInstance(){
    
       return hungry;
   }
}

notes 】 This single case is not safe , We can destroy this single case with reflection .

Use reflection to destroy

class test{
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
    
Constructor<Hungry> declaredConstructor = Hungry.class.getDeclaredConstructor(null);
        // by true  Indicates that private members can be obtained 
        declaredConstructor.setAccessible(true); 
         // Failed to pass this singleton class u getInstance() Method   The instance is created .
        Hungry hungry = declaredConstructor.newInstance();
    }
}

The sluggard model

It means 】 Instances of classes are created only when needed

advantage 】 Multithreading is not safe

**【 shortcoming 】** Must be locked. synchronized To guarantee the single case , But locking can affect efficiency .getInstance() Performance is not critical for applications ( This method is not used frequently )

package com.singleton;

/** *  Create an instance when you want to use it  */
public class Lazy {
    
     private Lazy(){
    
        System.out.println(" Threads "+Thread.currentThread().getName()+" Created an instance ");
    }
    private static Lazy lazy ;

    // There will be thread safety issues ,
    public static  Lazy getInstance(){
    
        if(lazy == null){
    
            lazy = new Lazy();
        }
        return  lazy;
    }
}

Simulating multithreading is not safe

class test2{
    
    public static void main(String[] args) {
    
        for (int i = 0; i < 5; i++) {
    
            new Thread(()->{
    
                Lazy.getInstance();
            },i+"").start();
        }
    }
}
/* Output :  Threads 1 Created an instance   Threads 3 Created an instance   Threads 4 Created an instance   Threads 2 Created an instance   Threads 0 Created an instance  */

Why does this happen ?

Command rearrangement , And creating an instance is not an atomic operation .

The order in which instances are created :

1、 Allocate memory space

2、 Execute construction 、 Initialize object

3、 Point this object to this memory space

When it comes to multithreading , Will appear ——A The thread is not finished ,B The thread came and was found to be null Continue creating objects .

notes 】 Reflection can still be used to destroy this single case

Use reflection to destroy

class test2{
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
        
   Constructor<Lazy> declaredConstructor = Lazy.class.getDeclaredConstructor(null);
        // by true  Indicates that private members can be obtained 
        declaredConstructor.setAccessible(true); 
        // Failed this single case  getInstance() Method   You get an example .
        Lazy lazy = declaredConstructor.newInstance();
        
    }
}

DCL The sluggard model

What is? DCL?

DCL Also called Double check lock / Double check lock (DCL, namely double-checked locking).

In other words, we double check this single case , And lock it . Prevent unsafe multithreading .

advantage 】 Multithreading security

package com.singleton;

public class DCLLazy {
    
    private DCLLazy() {
    }
    //volatile Prevent command rearrangement ,synchronized You can guarantee atomicity 
    private static volatile DCLLazy dclLazy = null;

    public static DCLLazy getInstance(){
    
        // If this instance is not empty, other threads cannot come in , It can also prevent threads from repeatedly getting locks , Waste resources 
        if (dclLazy == null) {
    
            // When the first thread enters, it will lock this class 
            synchronized (DCLLazy.class) {
    
                if (dclLazy == null) {
    
                    dclLazy = new  DCLLazy();
                }
            }
        }
       return  dclLazy;
    }
}

notes 】 It still can't prevent the single case of reflection destruction

Use reflection to destroy

class  test3{
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
       
Constructor<DCLLazy> declaredConstructor = DCLLazy.class.getDeclaredConstructor(null);
       DCLLazy dclLazy = declaredConstructor.newInstance();
       DCLLazy dclLazy2 = declaredConstructor.newInstance();
       System.out.println(dclLazy.equals(dclLazy2)); // Output false , The description is not the same object 
    }
}

So let's give this DCL Strengthen under , Add... To the structure

 private DCLLazy() {
    
  		 synchronized (DCLLazy.class) {
     // Lock , Ensure atomicity under multithreading 
            if (judge == false) {
     // The first instance created is false, And modify it judge by true
                judge = true;
            } else {
    
                throw new RuntimeException(" Don't use reflection to destroy ");
            }
        }
    }

Run again main Method , I found the wrong report , The console appears and we throw an exception , Does that mean it's solved ? Not at all , Reflection can take private properties and change values .

Caused by: java.lang.RuntimeException:  Don't use reflection to destroy 
	at com.singleton.DCLLazy.<init>(DCLLazy.java:15)
	... 6 more

Modify reflection code :

class test3 {
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
    
        Field judge = DCLLazy.class.getDeclaredField("judge"); // Get attributes 
        judge.setAccessible(true);
Constructor<DCLLazy> declaredConstructor =DCLLazy.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        // Created the first instance 
        DCLLazy dclLazy = declaredConstructor.newInstance(); 
        
		// Show up and put judge Property set to false, So you can continue to create instances 
        judge.set(declaredConstructor,false); 

        DCLLazy dclLazy2 = declaredConstructor.newInstance();
        // Still output false , It means that it is still not the same object 
        System.out.println(dclLazy.equals(dclLazy2)); 
    }
}

Static inner class

Lazy loading is realized , Only when the inner class is called , Will be loaded by the class loader .

advantage 】 Multithreading security , This way can achieve the same effect of double lock , But it's easier to achieve

package com.singleton;

public class StaticSingleton {
    
    private StaticSingleton(){
    }

    public StaticSingleton getInstance(){
    
        return instanceClass.STATIC_SINGLETON;
    }

    // Static inner class 
    public static class instanceClass{
    
   private  static final  StaticSingleton STATIC_SINGLETON = new StaticSingleton();
    }
}

notes 】 You can still destroy this single case with reflection

Reflection damage


class test4{
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
        Constructor<StaticSingleton> declaredConstructor = StaticSingleton.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true); // by true  Indicates that private members can be obtained 
        StaticSingleton ss = declaredConstructor.newInstance(); // Failed this single case  getInstance() Method   You get an example .
    }
}

enumeration

advantage 】 This implementation has not been widely adopted , But this is the best way to implement the singleton pattern . It's simpler , Automatic support for serialization mechanism , Absolutely prevent multiple instantiations , Multithreading security .

** describe :** This implementation has not been widely adopted , But this is the best way to implement the singleton pattern . It's simpler , Automatic support for serialization mechanism , Absolutely prevent multiple instantiations .
This way is Effective Java author Josh Bloch Ways to advocate , It not only avoids the multithreaded synchronization problem , It also automatically supports serialization mechanism , Prevents deserialization from recreating new objects , Absolutely prevent multiple instantiations . however , because JDK1.5 After that enum characteristic , It feels strange to write in this way , In practice , Rarely use .
Cannot pass reflection attack To call the private constructor .

notes 】 Can prevent reflection .

public enum  EnumSingleton {
    
    INSTANCE;
     public void outPut(){
    
        System.out.println(" In a trance ");
    }
}

Let's take a look at the compiled class file :

Found compiled class file There is a private construction method , Let's try to see if reflection can call this construct .

package li;

public enum EnumSingleton {
    
    INSTANCE;

    private EnumSingleton() {
    
    }

    public void outPut() {
    
        System.out.println(" In a trance ");
    }
}

Use reflection to try to destroy

class test5{
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
        Constructor<EnumSingleton> declaredConstructor = EnumSingleton.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        EnumSingleton enumSingleton = declaredConstructor.newInstance();
        enumSingleton.outPut();
    }
}

I found the wrong report , Tell us , There is no such construction method .

Exception in thread "main" java.lang.NoSuchMethodException: li.EnumSingleton.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.getDeclaredConstructor(Class.java:2178)
	at li.test5.main(EnumSingleton.java:15)

We use jad decompile , First open jad, And then in cmd Input :jad -sjava EnumSingleton.class

Then there was a java Suffix source file :

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name: EnumSingleton.java

package li;

import java.io.PrintStream;

public final class EnumSingleton extends Enum
{
    

    public static EnumSingleton[] values()
    {
    
        return (EnumSingleton[])$VALUES.clone();
    }

    public static EnumSingleton valueOf(String name)
    {
    
        return (EnumSingleton)Enum.valueOf(li/EnumSingleton, name);
    }
	
	// Look here , The discovery is a parametric construction method with two parameters 
    private EnumSingleton(String s, int i)
    {
    
        super(s, i);
    }

    public void outPut()
    {
    
        System.out.println("\u7EA2\u706B\u706B\u604D\u604D\u60DA\u60DA");
    }

    public static final EnumSingleton INSTANCE;
    private static final EnumSingleton $VALUES[];

    static 
    {
    
        INSTANCE = new EnumSingleton("INSTANCE", 0);
        $VALUES = (new EnumSingleton[] {
    
            INSTANCE
        });
    }
}

Let's use reflection to see if we can use this parametric structure

class test5{
    
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    
        // Construct with parameters 
 Constructor<EnumSingleton> declaredConstructor = 	      EnumSingleton.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        
        EnumSingleton enumSingleton = declaredConstructor.newInstance();
        enumSingleton.outPut();
    }
}

Throw an exception : Tell you you can't use reflection to create enumerated objects

Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
	at li.test5.main(EnumSingleton.java:17)

summary

In general , It is not recommended to use 2 The lazy way , It is recommended to use section 1 The way of starving people . Only if we want to realize lazy loading In effect , Will use the 4 A static inner class method . If it comes to deserialization when creating objects , You can try using section 5 There are several ways to enumerate . If there are other special needs , Consider using section 3 Double lock mode .

eighteen 、 In depth understanding of CAS

What is? CAS?

Is to compare and exchange

nineteen 、 Atomic reference

What is atomic reference ?

The main physical memory has a shared variable value of 5, There are two threads T1,T2, They all have their own working memory , And there are copies of variables ( snapshot 5),T1 The thread now changes the value to 2019, then , Write back to main physical memory and notify other threads to see ( Add volatile), In the process .T1 The expected value of 5, To match the value of the main physical memory 5 Contrast , If the same , No other thread changes , Change the value of the main physical memory to 2019, And back to true. At this time ,T2 The thread also changes the value of its working memory to 1024, however , When writing back to main physical memory , Find your expectations (5), With the current main physical memory (2019) It's different. , Will fail to write , return false, At this point, you need to retrieve the new value of the main physical memory
————————————————
Link to the original text :https://blog.csdn.net/qq_38826019/article/details/110704711

Optimism lock , Set version number

public final class EnumSingleton extends Enum
{

public static EnumSingleton[] values()
{
    return (EnumSingleton[])$VALUES.clone();
}

public static EnumSingleton valueOf(String name)
{
    return (EnumSingleton)Enum.valueOf(li/EnumSingleton, name);
}

// Look here , The discovery is a parametric construction method with two parameters 
private EnumSingleton(String s, int i)
{
    super(s, i);
}

public void outPut()
{
    System.out.println("\u7EA2\u706B\u706B\u604D\u604D\u60DA\u60DA");
}

public static final EnumSingleton INSTANCE;
private static final EnumSingleton $VALUES[];

static 
{
    INSTANCE = new EnumSingleton("INSTANCE", 0);
    $VALUES = (new EnumSingleton[] {
        INSTANCE
    });
}

}


 Let's use reflection to see if we can use this parametric structure 

```java
class test5{
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // Construct with parameters 
 Constructor<EnumSingleton> declaredConstructor = 	      EnumSingleton.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        
        EnumSingleton enumSingleton = declaredConstructor.newInstance();
        enumSingleton.outPut();
    }
}

Throw an exception : Tell you you can't use reflection to create enumerated objects

Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
	at li.test5.main(EnumSingleton.java:17)

summary

In general , It is not recommended to use 2 The lazy way , It is recommended to use section 1 The way of starving people . Only if we want to realize lazy loading In effect , Will use the 4 A static inner class method . If it comes to deserialization when creating objects , You can try using section 5 There are several ways to enumerate . If there are other special needs , Consider using section 3 Double lock mode .

eighteen 、CAS

CAS Is used to ensure the thread safety of atomic classes .
stay jdk5 Used to sync Lock to achieve , It needs to be locked .

CAS Is to compare and exchange

nineteen 、 Atomic reference

What is atomic reference ?

The main physical memory has a shared variable value of 5, There are two threads T1,T2, They all have their own working memory , And there are copies of variables ( snapshot 5),T1 The thread now changes the value to 2019, then , Write back to main physical memory and notify other threads to see ( Add volatile), In the process .T1 The expected value of 5, To match the value of the main physical memory 5 Contrast , If the same , No other thread changes , Change the value of the main physical memory to 2019, And back to true. At this time ,T2 The thread also changes the value of its working memory to 1024, however , When writing back to main physical memory , Find your expectations (5), With the current main physical memory (2019) It's different. , Will fail to write , return false, At this point, you need to retrieve the new value of the main physical memory
————————————————
Link to the original text :https://blog.csdn.net/qq_38826019/article/details/110704711

Optimism lock , Set version number

原网站

版权声明
本文为[Independent fence window]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/175/202206240556091336.html