java review series [2] - Java multithreading

JUC

thread

Joe Armstrong, the father of Erlang, explained the difference between concurrency and parallelism with a diagram that can be understood by a 5-year-old

Concurrency is that two queues use a coffee machine alternately,

Parallel is two queues using two coffee machines at the same time

Concurrency: multiple threads access the same value

Parallel: doing multiple things at the same time

Thread state

[external chain picture transfer fails, and the source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-SzqoILVk-1638360355868)(Java multithreading. Assets / watermark, type_zmfuz3pozw5nagvpdgk, shadow_10, text_ahr0chm6ly9ibg9nlmnzg4ubmv0l3fxzm2nzm5mdqw, size_16, color_ffff, t_70-16308262392821. PNG)]

stateintroduce
1NewA new Thread object is in Java
At this time, it only allocates memory in the heap
2Runnable: Runnable state (create JVM stack and PC)
: ReadyWait for the system to allocate CPU resources
: RunningRunning, only Ready status can be changed to running
Blocked: Blocking status (timeout, wait, blocking)
3: Time WaitWhen the current thread executes the sleep() method, or calls the join() method of other threads, or makes an I/O request, it will enter this state.
4: WaitIn the running state, the wait() method of an object is (actively) executed
5: BlockedThe lock was not acquired, and the (passive) block is in the queue
6DeadWhen a thread exits the run() method, it enters a dead state, and the thread ends its life cycle
public enum State {
    
    /**
    * Thread state for a thread which has not yet started.
	*/ 
    NEW,   
	/**
     * Thread state for a runnable thread.  A thread in the runnable
     * state is executing in the Java virtual machine but it may
     * be waiting for other resources from the operating system
     * such as processor.
     */
    RUNNABLE,

    /**
     * Thread state for a thread blocked waiting for a monitor lock.
     * A thread in the blocked state is waiting for a monitor lock
     * to enter a synchronized block/method or
     * reenter a synchronized block/method after calling
     * {@link Object#wait() Object.wait}.
     */
    BLOCKED,

    /**
     * Thread state for a waiting thread.
     * A thread is in the waiting state due to calling one of the
     * following methods:
     * <ul>
     *   <li>{@link Object#wait() Object.wait} with no timeout</li>
     *   <li>{@link #join() Thread.join} with no timeout</li>
     *   <li>{@link LockSupport#park() LockSupport.park}</li>
     * </ul>
     *
     * <p>A thread in the waiting state is waiting for another thread to
     * perform a particular action.
     *
     * For example, a thread that has called <tt>Object.wait()</tt>
     * on an object is waiting for another thread to call
     * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
     * that object. A thread that has called <tt>Thread.join()</tt>
     * is waiting for a specified thread to terminate.
     */
    WAITING,

    /**
     * Thread state for a waiting thread with a specified waiting time. A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
     * <ul>
     *   <li>{@link #sleep Thread.sleep}</li>
     *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
     *   <li>{@link #join(long) Thread.join} with timeout</li>
     *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
     *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
     * </ul>
     */
    TIMED_WAITING,

    /**
     * Thread state for a terminated thread. The thread has completed execution.
     */
    TERMINATED;
}

Similarities and differences between sleep() and wait()

**Common ground: * * both will pause the execution of the thread

sleep()wait()
methodStatic method of Thread classObject instance method
lockThe lock will not be releasedThe lock will be released
awakenWake up automatically when the time is upnotify(), notifyAll() wake up required
effectPause threadCombined with notify(), notifyAll(), it can be used for thread synchronization

Similarities and differences between wait() and blocking

**Common ground: * * both will pause the execution of the thread

wait()block
Active and passiveActive entryPassive entry
positionsynchronized internalsynchronized external
lockEntering the synchronization code block,
The lock will be released when calling wait
Blocking because no lock was acquired
scope of executionsynchronized synchronization block (method) internalAny position

Some Question !!!

With sleep(), why wait(time)?

wait(time) will release the lock while waiting, so that other threads can acquire the lock and execute the task!

Thread interrupt

interrupt() is based on "a thread should not be forcibly interrupted or stopped by other threads, but should be stopped by the thread itself."

Remember that interrupt() does not really interrupt threads. The called thread needs to cooperate by itself. In other words, if a thread needs to be interrupted, it needs to do so:

  1. When running a task normally, always check the interrupt flag bit of the thread. If the interrupt flag is set, the thread will stop by itself.
  2. Handle the InterruptedException exception correctly when calling the blocking method. (for example, the thread ends after a catch exception.)
   // Core interrupt method
   public void interrupt() {
        if (this != Thread.currentThread()) // Not this thread, you need to check permissions
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Only the interrupt flag bit is set
                b.interrupt(this);    // Call the interrupt method as defined by the I/O operation
                return;
            }
        }
        interrupt0();
    }
    // Static method. This method is a little pit. After calling this method, the interrupt state will be cleared.
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    // This method does not clear the interrupt state
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
   // The above two methods will call this local method, and the parameter represents whether to clear the interrupt state
   private native boolean isInterrupted(boolean ClearInterrupted);

Interrupt example

Interrupt thread

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.start();
        Thread.sleep(1); // Pause for 1 ms
        t.interrupt(); // Interrupt t thread
        t.join(); // Wait for the t thread to end
        System.out.println("end");
    }
}

class MyThread extends Thread {
    public void run() {
        int n = 0;
        while (! isInterrupted()) {
            n ++;
            System.out.println(n + " hello!");
        }
    }
}
  1. Look carefully at the above code. The main thread interrupts the T thread by calling the t.interrupt() method, but note that the interrupt() method only sends an "interrupt request" to the T thread. Whether the T thread can respond immediately depends on the specific code. The while loop of T thread will detect isInterrupted(), so the above code can correctly respond to the interrupt() request and make itself immediately end running the run() method.

  2. If the thread is in the waiting state, for example, t.join() will make the main thread enter the waiting state. At this time, if interrupt() is called on the main thread, the join() method will immediately throw an InterruptedException. Therefore, as long as the target thread catches the InterruptedException thrown by the join() method, it indicates that other threads have called the interrupt() method, Normally, the thread should end immediately.

Memory occupied by threads

How much memory does java thread occupy and where

  1. Thread private JVM stack, - Xss can set its memory footprint
  2. For each new thread in Java, the JVM will request the operating system to start a new local thread. At this time, the operating system will allocate this thread with free memory space. Therefore, threads in java do not occupy the memory space of the JVM, but the free memory space of the operating system

Some Question !!!

Thread context switching?

  1. During thread scheduling, after the time slice of the current thread runs out, you need to switch to the next thread.
  2. When switching, you need to save other information (PC, stack information)

Three features of JMM

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-g9y4tk5y-163836055869) (Java multithreading. assets/image-20210905105804780.png)]

  • Atomicity
  • visibility
  • Order

volatile

java keyword for lightweight thread synchronization

How to ensure visibility?

Solving concurrency visibility using MSEI cache consistency protocol

  1. After the thread modifies the value in the working memory, it will use atomic operations such as store/write to modify the value of the main memory
  2. And trigger the sniffing mechanism to invalidate the variable copies of other threads

MESI protocol

Function:

Ensure that the copies of shared variables used in each Cache are consistent

The core idea of MESI: when the CPU writes data, if it is found that the variable of the operation is a shared variable, that is, there are copies of the variable in other CPUs,

It will send a signal to inform other CPU s to set the cache line of the variable to an invalid state (sniffing mechanism),

Therefore, when other CPU s need to read this variable and find that the cache line caching this variable in their own cache is invalid, it will be re read from memory.

Monitoring and notification: Based on bus sniffing mechanism

Four states:

MESI - Modified, Exclusive, Shared, Invalid

  1. Modify: when the data in the cache line is modified, the cache line is set to M status
  2. Exclusive: set to E state when only one cache row uses a certain data
  3. Shared: when other CPU s also read some data to the cache line, all cache lines holding the data are set to S state
  4. Invalid: when the data of a cache line is modified, other cache lines holding the data are set to I status
Process example:
  1. CPU1 reads the main memory data A = 1, and CPU1 saves A copy of data A in the cache. The cache state is E
  2. CPU2 reads the main memory data A=1, and CPU2 stores A copy of data A in the cache. At this time, the sniffing mechanism finds that CPU1 also has the data in the cache, so CPU1 and CPU2 are set to S
  3. CPU1 modifies CPU1 cache A=2 and main memory A=2. At the same time, CPU1'S cache state is set to S, the bus sends a notification, and CPU2'S cache state changes to I
  4. CPU2 reads A again. Although CPU2 hits data A = 1 in the cache, it finds that the status is I, so it directly discards the data and obtains the latest data of A in main memory

If CPU2 does not read A again after CPU1 modifies the cache (that is, there is no step 4), but directly operates on A after step 2, and then modifies the value of A, then it may conflict with the operation in step 3, resulting in only one modification being valid!!!

This is also the reason why atomicity cannot be guaranteed!!!

Understanding Java Concurrency: how volatile ensures visibility

How to ensure order?

First answer a question, why do you need to rearrange instructions?

In order to improve efficiency!

Java optimizes instructions, and instruction rearrangement may occur during the optimization process.

How does volatile prohibit instruction rearrangement?

Add memory barrier to volatile modified variables!

Working principle of memory barrier:

Insert a memory barrier between instructions and prohibit cpu from reordering volatile modified variables, that is, insert a memory barrier to prohibit reordering optimization before and after the memory barrier

Specific implementation:

In the variable of volatile, an assembly instruction prefixed with lock will be added.

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (IMG kduiahpp-163836055870) (Java multithreading. assets/webp.webp)]

Why not guarantee atomicity?

volatile int state = 100;
state++;

volatile int state = 100; Modifying the state variable is divided into four steps:

  1. Read state to working memory
  2. Modify variable value
  3. The state in the working variable is written back to main memory
  4. Insert a memory barrier (lock instruction) to make it visible to other threads

In step 1, 2 and 3, there is no guarantee that no other thread will modify it. In other words, in the third step, it is not judged whether the state is changed in main memory;

  1. Thread reads state

  2. temp =state + 1 3, state = temp when i=5, threads A and b read the value of state at the same time, and then thread A performs the operation of temp =state + 1,

  3. Note that the value of i has not changed at this time, and then thread B also performs the operation of temp = state + 1. Note that at this time, the value of state saved by threads A and B is 5 and the value of temp is 6,

  4. Then thread A performs the operation of state = temp (6). At this time, the state value will be immediately refreshed to the main memory and notify other threads that the saved state value is invalid,

  5. At this time, thread B needs to re read the value of i. at this time, the i saved by thread B is 6, and the temp saved by thread B is still 6. Then thread B executes state = temp (6), so the calculation result is 1 less than expected

    Why can't volatile guarantee atomicity (see comments)

CAS

The native method of Unsafe class is to call the system primitive, so it is atomic.

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-zgjopiuv-163836055871) (Java multithreading. assets/image-20210830102907515.png)]

CAS defect

  1. If CAS fails, it will keep trying, and the CPU overhead is high (when the concurrency is large, the efficiency is low)
  2. It just guarantees the atomic operation of a shared variable
  3. ABA problem

ABA problem

Add version number control

ABA -> A1B2A3

synchronized and CAS

Synchronized allows only one thread to run. Although the consistency is guaranteed, the concurrency is reduced. The bottom layer of cas is unsafe and unlocked to ensure consistency. Multiple threads are allowed to operate at the same time, and the concurrency is guaranteed, but the cycle is compared

synchronized

After thread A obtains the lock, other threads enter the blocking state, and thread A ends; The thread switches the context

Waste of resources in context switching comparison

[external chain image transfer fails, and the source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-SLhSHDWw-1638360355872)(Java multithreading. Assets / watermark, type_zmfuz3pozw5nagvpdgk, shadow_10, text_ahr0chm6ly9ibg9nlmnzg4ubmv0l3fxzm2nzm5mdqw, size_16, color_ffff, t_70. PNG)]

synchronized keyword

synchronized keyword

The synchronized keyword solves the synchronization of accessing resources between multiple threads. The synchronized keyword can ensure that only one thread can execute the modified method or code block at any time.

The JVM synchronizes methods and synchronization blocks by entering and exiting the object monitor, and the essence of the object monitor depends on the mutex lock of the underlying operating system.

Specific implementation:

In the compiled bytecode, add a monitorenter instruction before the synchronous method call, and insert the monitorexit instruction at the exit method and exception.

Use of synchronized

[external chain picture transfer fails, and the source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-n6UsUUEH-1638360355872)(Java multithreading. Assets / watermark, type_zmfuz3pozw5nagvpdgk, shadow_10, text_ahr0chm6ly9ibg9nlmnzg4ubmv0l3fxxzm2nzm5mdqw, size_16, color_ffff, t_70. PNG)]

synchronized lock upgrade

User mode and kernel mode:

  • User status: the running status of the user program
  • Kernel state: control the core resources of the computer, hardware, CPU scheduling, memory allocation, etc
  • If the user mode program wants to use the kernel mode function, it must use the system call interface

Simply put, the underlying principle of synchronized heavyweight locks in the JVM:

The bytecode of monitorenter and monitorexit depends on the Mutex Lock of the underlying operating system. However, using Mutex Lock requires suspending the current thread and switching from user state to kernel state, which is very expensive.

JDK is a heavyweight lock until 1.5 and before. 1.6 is optimized: no lock - bias lock - spin lock (lightweight lock) - heavyweight lock

Reasons for optimization:

The acquisition and release of heavyweight locks need to go through the operating system, which is a heavyweight operation:

  1. For heavyweight locks, once the lock acquisition fails, they will fall into a blocking state (OS level blocking), which involves the switching from user state to core state of mind (this operation is very expensive)
  2. On the research surface, the thread holds the lock for a short time (even if the lock cannot be obtained at present, the lock can be obtained soon. Blocking the thread in this case will cause a waste of resources)

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-0hjystrq-163836055873) (Java multithreading. assets/image-20210817155045536.png)]

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-xIxXy0jA-1638360355873)(Java multithreading. assets/image-20210825105831885.png)]

Unlocked state

Bias lock

Research shows that lock resource competition does not occur in most scenarios. In this case, the same thread obtains the lock. If it needs to obtain the lock, a series of operations (CAS spin) are required. Such operations are resources.

Then the lock will enter the bias mode. When the same thread requests the lock again, it does not need to do any synchronization, but directly execute the synchronization area. In this way, a large number of operations related to lock application are omitted.

In the case of no lock competition, biased lock has great optimization effect

Lightweight Locking

Heavyweight lock

Title: what's the difference between synchronized and Lock? What are the benefits of using the new Lock? Give me an example

synchronizedReentrantLock
ImplementationJVM level implementationClasses in JUC
UseUse on methods and method blocksUse the lock and unlock methods
lockUnfair lockNon fair lock (default) and fair lock
Is waiting interruptibleIt shall not be interrupted unless abnormal and normal end occursInterruptible,
1. Set the timeout method tryLock(long, unit)
2. lockInterruptibly() is placed in the code block, and the interrupt method can be interrupted.
Precise wake-upnotify() random wake-up
notifyAll() wake up randomly
The signal of Condition can wake up accurately
  1. Original composition:
    1. synchronized is a JVM level keyword; (heavyweight lock) the bottom layer is completed through the monitor object. In fact, the wait and notify methods also depend on the monitor object (so the wait and notify methods can only be called in the synchronous method block or method)
    2. Lock is an interface in JUC and an API level lock. It is implemented based on CAS
  2. usage method
    1. Manual release by the user is not required
    2. The lock needs to be released manually, otherwise it may cause deadlock
  3. Is waiting interruptible
    1. synchronized cannot be interrupted unless abnormal and normal connections occur
    2. ReentrantLock can be interrupted, 1. set timeout method tryLock(long, unit) 2. lockInterruptibly() into the code block, calling interrupt method can interrupt.
  4. Is locking fair
    1. synchronized unfair lock
    2. ReentrantLock is a non fair lock by default. You can set fair or non fair locks
  5. Lock binding multiple conditions
    1. synchronized no; notify is to wake up a thread randomly, and nodifyAll() is to wake up all threads
    2. RenentrantLock is used to wake up a thread that needs to be awakened by a group. It can wake up a thread accurately

Join

The principle and use of join() method in Java

ublic static void main(String[] args) {
    Runnable runnable = new Runnable() {
			@Override
			public void run() {
				System.out.println("Sub thread execution");
			}
		};
    Thread thread1 = new Thread(runnable);
    Thread thread2 = new Thread(runnable);
    thread1.start();
    thread2.start();
    try {
        //The main thread starts waiting for child threads thread1 and thread2
        thread1.join();
        thread2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    //Wait until both threads are finished (inactive) before executing downlink printing
    System.out.println("completion of enforcement")`;;
}

In the join source code, wait() is called.

public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }
    if (millis == 0) {
        // The key implementation is to wait permanently through the wait method on this line.
        while (isAlive()) { // Determine whether the current thread is alive
            wait(0);		// Let the thread calling the join method wait (in the above example, the main thread waits)
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}
        // The key implementation is to wait permanently through the wait method on this line.
        while (isAlive()) { // Determine whether the current thread is alive
            wait(0);		// Let the thread calling the join method wait
        }
// Let the thread calling the join method wait (in the above example, the main thread waits)
// In the above example, calling the join() method is the main thread.

Some problems

Switching from user state to core state of mind?

Collection class insecurity

Concurrency of ArrayList

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-SuC2zF4c-1638360355874)(Java multithreading. assets/image-20210710093617362.png)]

  1. Fault phenomenon

    java.util.ConcurrentModificationException

  2. Causes

    Concurrent contention modification, one thread is writing, and another thread has to write. ArrayList is thread unsafe

  3. Solution

    1. Lock
    2. Thread safe collection class
      1. Vector
      2. Collections.synchronizedList(new ArrayList())
      3. CopyOnWriteArrayList, copy on write
  4. Optimization suggestions (the same error does not occur the second time)

Concurrency of HashSet

Similar to ArrayList, CopyOnWriteArrayList is used internally.

The bottom layer of HashSet is HashMap, but why is it just a value?

The Key is placed in the HashSet, and the private static object is placed in the Value; In other words, the values in all hashsets are stored as PRESENT.

private static final Object PRESENT = new Object();

public boolean add(E e) {
      return map.put(e, PRESENT)==null;  
}

HashMap

HashTable

ConcurrentHashMap

Thread safe collection

CopyOnWriteXXX

    private E get(Object[] a, int index) {        return (E) a[index];    }
    public boolean add(E e) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            Object[] newElements = Arrays.copyOf(elements, len + 1);            newElements[len] = e;            setArray(newElements);            return true;        } finally {            lock.unlock();        }    }

When reading, it is not locked. What is read is a copy

When writing, lock it, create a new copy for writing, and then overwrite the original version

Question: when you modify CopyOnWriteXXX, how can you ensure that other threads will not get data errors when overwriting the original version?

Don't enter the misunderstanding! Other threads only read data before and after overwriting the original version. In the previous case, the previous data address is accessed, and in the later case, the new data address is accessed.

When A thread obtains data, it will get the reference in the current data array and access it

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-cmx92ynf-163836055875) (Java multithreading. assets/image-20210905161135425.png)]

Fair lock, unfair, reentrant (recursive), spin

Fair lock and unfair lock

Fair: first come, first served, queue up in the order of application

Unfair: snatch (ReentrantLock and synchronized default)

About the difference between the two
Fair lock:

Fair lock is fair. In a concurrent environment, each thread will first view the waiting queue maintained by the lock when acquiring the lock. If it is empty or the current thread is the first in the waiting queue, it will occupy the lock. Otherwise, it will be added to the waiting queue and get itself from the queue according to FIFO rules in the future

Unfair lock:

Unfair locks are rude. When you come up, you directly try to possess the lock. If the attempt fails, you can use a method similar to fair locks.

Unfair locks have three opportunities to obtain locks before entering the queue:

  1. Calling lock() will immediately attempt to acquire the lock
  2. When determining whether to queue, it will try to obtain the lock
  3. Before entering the queue, the lock will be acquired again

Illustrates the process of obtaining fair and unfair locks

Reentrant lock

It means that after the outer function of the same thread obtains the lock, the inner recursive function can still obtain the code of the lock. When the same thread obtains the lock in the outer method, it will automatically obtain the lock when entering the inner method; That is, a thread can enter any code block synchronized with a lock it already has.

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-attqajaj-163836055876) (Java multithreading. assets/image-20210825104508087.png)]

Spin (Unsafe + CAS)

This means that the thread trying to acquire the lock will not block immediately, but will try to acquire the lock in a circular way. This has the advantage of reducing the consumption of thread context switching, but the disadvantage is that the cycle will consume CPU

In synchronized, it is called lightweight lock

Also known as Le Guan lock

The essence of spin is: while loop + CAS

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-mlgop0ve-163836055877) (Java multithreading. assets/image-20210710102523261.png)]

Exclusive (write) and shared (read)

Before, no matter reading or writing, it was only a thread that could operate.

Now separate reading and writing, share when reading and exclusive when writing

ReentrantReadWriteLock: exclusive when writing and shared when reading

CountDownLatch

Let some threads block until another thread completes a series of operations.

CountDownLatch has two main methods:

  1. When one or more threads call the await method, the calling thread is blocked.
  2. When other threads call the countDown method, the counter will be decremented by 1 (the thread calling the countDown method will not be blocked). When the counter value becomes zero, the thread blocked by calling the await method will be awakened and continue to execute.

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-z29obcsr-163836055877) (Java multithreading. assets/image-20210710112035424.png)]

The door closes when people are finished

In order to simulate high concurrency, let a group of threads rush to buy at a specified time (second kill time). After these threads are ready, wait (CountDownLatch.await()) until the second kill time comes, and then rush forward; This is also a simple implementation of local test interface concurrency.

CyclicBarrier

Cyclic Barrier literally means a Barrier that can be used cyclically. What it needs to do is to block a group of threads when they reach a Barrier (also known as synchronization point). The Barrier will not open until the last thread reaches the Barrier, and all threads intercepted by the Barrier will continue to work. Threads enter the Barrier and pass through the await() method of cyclicbarrier.

Collect 7 dragon balls to summon the dragon

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-70qpvcf8-163836055878) (Java multithreading. assets/image-20210710113250060.png)]

The meeting was held only when all the people were present

Semaphore

Semaphores are mainly used for two purposes:

  1. One is for mutually exclusive use of multiple shared resources,

  2. The other is used to control the number of concurrent threads.

Example: 6 cars grab 3 parking spaces

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-2kjahibi-163836055878) (Java multithreading. assets/image-20210710113841697.png)]

7 blocking queues

In the multithreading field, the so-called blocking will suspend the thread (i.e. blocking) in some cases. Once the conditions are met, the suspended thread will be awakened automatically

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-xfzzdyhj-163836055879) (Java multithreading. assets/image-20210710120904885.png)]

namedescribe
ArrayBlockingQueueBounded, array implementation, FIFO, support fair and unfair locks
LinkedBlockingQueueBounded (default Integer.MAX_VALUE), linked list implementation, FIFO
SynchronousQueueBounded (one element) does not store the blocking queue of elements, and each out of queue operation must wait for the in queue operation
PriorityBlockingQueueUnbounded, priority can be specified (default natural order)
DelayBlockingQueueUnbounded, Time can be specified, and can only be obtained after Time
LinkedTransferQueueUnbounded, linked list, more transfer and tryTransfer methods
LinkedBlockingDequeElements can be added and removed from two-way queues, head and tail

ArrayBLockingQueue:

Is a bounded blocking queue based on array structure, which sorts elements according to FIFO (first in first out) principle.

LinkedBLockingQueue (although bounded, the boundary is Integer.MAX_VALUE):

A blocking queue based on linked list structure. This queue is intended to sort elements in ftfo (first in first out), and the throughput is usually higher than that of ArrayBLockingQueue.

	// You can set the size of the blocking queue. 	 public LinkedBlockingQueue() {        this(Integer.MAX_VALUE);    }   	 public LinkedBlockingQueue(int capacity) {        if (capacity <= 0) throw new IllegalArgumentException();        this.capacity = capacity;        last = head = new Node<E>(null);    }

SynchronousQueue:

A blocking queue that does not store elements. Each insert operation must wait until another thread calls the remove operation. Otherwise, the insert operation is always blocked and the throughput is usually high

BlockingQueue uses:

methodabnormalSpecial valueblockovertime
Join the teamadd(e)offer(e)put(e)offer(e, time)
Out of the teamremove()poll()take()poll(e, time)
inspectelement()peek()--
situationExplanation: when the queue is full or empty, the processing method after entering and leaving the queue
abnormalThrow exception
Special valueReturns a boolean value indicating whether it is successful
blockBlocked to available
overtimeBlock for a period of time, and cancel the operation after timeout (out of line or in line)

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-okhwkdes-163836055880) (Java multithreading. assets/image-20210710123304213.png)]

Condition

Classes that provide wait and notify functions corresponding to the Object class;

Corresponding methods: await and signal methods

Thread pool

Callable

  1. Thread has no Callable interface method. How to use it
  2. How to get the return value of Callable

The traditional Thread construction method has no Callable construction method, so a middleware (RunnableFuture) is used to deal with this problem.

Runable Future

RunableFuture

FutureTask (implementation class)

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-I3LNzpRM-1638360355880)(Java multithreading. assets/image-20210710233419770.png)]

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-2ptyxup2-163836055881) (Java multithreading. assets/image-20210710233648847.png)]

Four basic thread pools

Executors class creates a thread pool:

  • FixedThreadPool
  • SingleThreadPool
  • CachedThreadPool
  • ScheduledThreadPool
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue<Runnable>(), // Linked list, bounded (integer. Max_value) threadfactory);} Public static executorservice newsinglethreadexecutor() {return new finalizabledelegatedexecutorservice (New ThreadPoolExecutor (1, 1, 0l, timeunit.milliseconds, new linkedblockingqueue < runnable > ()); / / linked list, bounded (integer. Max_value)} Public static executorservice newcachedthreadpool() {return new ThreadPoolExecutor (0, integer. Max_value, 60L, timeunit. Seconds, new synchronousqueue < runnable > ()); / / there is no queue of elements. This method will always create threads} public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {/ / create a thread pool that supports timed and periodic task execution. In most cases, it can be used to replace the Time class. Return new scheduledthreadpoolexecutor (corepoolsize);} public scheduledthreadpoolexecutor (int corePoolSize,                                       ThreadFactory threadFactory) {        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,              new DelayedWorkQueue(), threadFactory);    }

FixedThreadPool and SingleThreadPool: a large number of requests are stacked, resulting in OOM

The number of threads is fixed (determined by the former user and 1 for the latter), but the maximum number of blocked queues allowed is Integer.MAX_VALUE. It is easy to accumulate a large number of requests, resulting in OOM

CachedThreadPool and ScheduledThreadPool: too many threads are created, resulting in OOM

The number of threads allowed to be created is Integer.MAX_VALUE, which may cause a large number of threads to be created, resulting in OOM

Therefore, Alibaba does not recommend using Executors to create thread pools, but wants to use ThreadPoolExecutor to create thread pools.

7 - basic parameters

  1. Number of core threads int corePoolSize
  2. Maximum number of threads int maximumPoolSize
  3. Non core thread lifetime long keepAliveTime
  4. Survival time unit
  5. Blocking queue BlockingQueue workQueue
  6. Thread factory ThreadFactory threadFactory
  7. Saturation policy rejectedexecutionhandler

Core thread

In general, the so-called core threads in the thread pool do not specifically refer to which threads are the core. Theoretically, the threads created in the thread pool may be destroyed, while the so-called core threads refer to the remaining threads under specific conditions (the number of threads is less than or equal to corePoolSize) and will not be destroyed!

When allowCoreThreadTimeOut is manually set to true, the core thread will survive for a certain time (keepAliveTime) like the largest thread and be destroyed

allowCoreThreadTimeOut is set to false by default

Allow core thread timeout destruction: executor.allowCoreThreadTimeOut(true);

4 - saturation strategy

  1. Discard the task and throw an exception (default) new ThreadPoolExecutor.AbortPolicy()
  2. Discard new ThreadPoolExecutor.DiscardPolicy() directly
  3. Discard the longest waiting task new ThreadPoolExecutor. Discardolddestpolicy()
  4. The task is processed by the calling thread new ThreadPoolExecutor.CallerRunsPolicy()

Calling thread: the thread that gives the task to the thread pool

Tips:

The RejectedExecutionHandler interface can be implemented according to the application scenario to customize the saturation strategy, such as logging or persistent storage of tasks that cannot be processed.

The first three are directly discarded, and the fourth is who calls who processes

Custom saturation policy

package com.company.Thread.Pool;import java.util.concurrent.*;public class TPExecutor {    public static void main(String[] args) {        ThreadPoolExecutor executor = new ThreadPoolExecutor(                3,                5,                1000,                TimeUnit.SECONDS,                new LinkedBlockingDeque(10),                Executors.defaultThreadFactory(),                new RejectPool());        for(int i=0; i<100; i++){            executor.execute(new Runnable() {                @Override                public void run() {                    System.out.println("-------------------------------");                }            });        }    }    static class RejectPool implements RejectedExecutionHandler {        public RejectPool(){}        @Override        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {            System.out.println("Custom reject policy");        }    }}

Thread pool lifecycle

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

**ctl: * * thread pool running state 3-bit runState and number of threads 29 bit workerCount

Five states of thread pool:

	private static final int RUNNING    = -1 << COUNT_BITS;    private static final int SHUTDOWN   =  0 << COUNT_BITS;    private static final int STOP       =  1 << COUNT_BITS;    private static final int TIDYING    =  2 << COUNT_BITS;    private static final int TERMINATED =  3 << COUNT_BITS;
running state State interpretation
RUNNINGThe thread pool works normally. It can submit new tasks or handle tasks that block the queue
SHUTDOWNThe thread pool is closed and does not accept new tasks, but will process tasks that block the queue
STOPWhen the thread pool is closed and new tasks are not accepted, the thread processing the task will be interrupted
TIDYINGAll tasks have been terminated, and the number of valid threads (all threads have ended) is 0
TERMINATEDEnter this state after the terminated method is executed

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-vtOqTuif-1638360355882)(Java multithreading. assets/image-20210810145859947.png)]

Worker thread

private final class Worker        extends AbstractQueuedSynchronizer        implements Runnable{        /** Thread this worker is running in.  Null if factory fails. */        final Thread thread;        /** Initial task to run.  Possibly null. */        Runnable firstTask;    }

How to create a Worker?

Two kinds of threads are created: core thread + maximum thread

How do I perform tasks in the blocking queue?

  1. Building Worker objects
        Worker(Runnable firstTask) {            setState(-1); // inhibit interrupts until runWorker            this.firstTask = firstTask;            this.thread = getThreadFactory().newThread(this);        }
  1. Run the Worker's run() method
        public void run() {            runWorker(this);        }
  1. run method calls runWorker method internally;

    • Where task = gettask())= Null is the core of performing the blocking Queue task

    • Lock: Worker inherits AQS. Lock: indicates that the current thread is executing tasks

      1. Lock: indicates that the current thread is executing a task

      2. If a task is executing, the thread should not be interrupted.

      3. If the thread is not in the exclusive lock state, that is, idle state, it indicates that it is not processing tasks. At this time, the thread can be interrupted

      4. When the thread pool executes the shutdown method or tryTerminate method, it will call the interruptIdleWorkers method to interrupt idle threads. The interruptIdleWorkers method will use the tryLock method to judge whether the threads in the thread pool are idle; If the thread is idle, it can be safely recycled.

        [the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-2dTanle7-1638360355882)(Java multithreading. assets/image-20210810155314103.png)]

    • Judge whether the process pool is STOP

    • Perform tasks

    • Unlock

  2. Worker thread recycling

    • Leave it to the garbage collection mechanism. The thread pool only maintains the thread references. When deciding which threads need to be recycled, clear their references.
final void runWorker(Worker w) {        Thread wt = Thread.currentThread();        Runnable task = w.firstTask;        w.firstTask = null;        w.unlock(); // allow interrupts        boolean completedAbruptly = true;         Try {/ / gettask() internally uses put and take blocking to get while (task! = null | (task = gettask())! = null) {w.lock() ; / / if pool is stopping, ensure thread is not interrupted; / / if not, ensure thread is not interrupted. This / / requires a check in second case to deal with / / shutdown now race while clearing interrupt / / 1. Judge whether the thread pool is stop if ((runstateatleast) (CTL. Get(), stop) | (thread. Interrupted() & & runstateatleast (CTL. Get(), stop)) & &! Wt.isinterrupted()) wt.interrupt(); / / 2. Execute the task try {beforeexecute (WT, task) ;                    Throwable thrown = null;                    try {                        task.run();                    } catch (RuntimeException x) {                        thrown = x; throw x;                    } catch (Error x) {                        thrown = x; throw x;                    } catch (Throwable x)  {                        thrown = x; throw new Error(x);                    } finally {                        afterExecute(task, thrown);                    }                } finally {                    task = null;                    w.completedTasks++;                    w.unlock();                }            } Completedabruptly = false;} finally {/ / when the task cannot be obtained, actively recycle your processWorkerExit(w, completedAbruptly);}}

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-tdu3deQF-1638360355883)(Java multithreading. assets/image-20210810160447481.png)]

Why does Worker implement AQS:

Ensure that it can respond to interrupts when idle and cannot be interrupted when executing tasks.

Why doesn't Worker use ReentrantLock????

ReentrantLock allows reentry.

When the thread pool is shut down or the size of the thread pool is modified, you need to get the lock first, that is, you can respond to interrupts when idle and can not be interrupted when executing tasks.

We implement a simple non-reentrant mutual exclusion lock rather than use ReentrantLock because we do not want worker tasks to be able to reacquire the lock when they invoke pool control methods like setCorePoolSize. Additionally, to suppress interrupts until the thread actually starts running tasks, we initialize lock state to a negative value, and clear it upon start (in runWorker).

Because we don't want the Worker to regain the lock when calling a thread pool control method such as setCorePoolSize.

In addition, to suppress interrupts before the thread actually starts running the task, we initialize the lock state to a negative value and clear it at startup

Worker s in the thread pool only need two states:

  • One is an exclusive lock, indicating that the task is being executed;
  • One is not locked, indicating an idle state.

How can workers call * * setCorePoolSize() * * and other methods when they focus on and run task s?

The following two methods can be overridden in ThreadPoolExecutor. They are called before task.run, so there is still this opportunity.

protected void beforeExecute(Thread t, Runnable r) { }protected void afterExecute(Runnable r, Throwable t) { }

Instance of ThreadPoolExecutor

package com.company.Thread;import java.util.concurrent.*;public class MyMain {    public static void main(String[] args){        ExecutorService executorService = new ThreadPoolExecutor(                2,                5,                1L,                TimeUnit.SECONDS,                new LinkedBlockingQueue<Runnable>(3),                Executors.defaultThreadFactory(),                new ThreadPoolExecutor.DiscardOldestPolicy()                /*  new ThreadPoolExecutor.CallerRunsPolicy()                * 	After the task is exceeded, more tasks are completed by the caller* 		:  In this example, it is the main thread* */                /*  new ThreadPoolExecutor.AbortPolicy()                *                * java.util.concurrent.RejectedExecutionException:                *       After the task exceeds the maximum number of threads + the number of blocking queues * this error is likely to be reported * for example, 5 + 3 < 9* */        );        try{            for(int i=1; i<=10; i++){                int finalI = i;                executorService.execute(() ->{                    System.out.println(                            Thread.currentThread().getName()                                    + "\t Handle the business" + finalI);                });            }        }catch (Exception e){            e.printStackTrace();        }finally {            executorService.shutdown();        }    }}

Reasonably configure the number of threads

There are two cases:

  1. CPU intensive
  2. IO intensive

CPU intensive:

This task requires a lot of computation without blocking, and the CPU runs at full speed all the time. CPU intensive tasks can be accelerated only on real multi-core CPUs (through multithreading),

In a single core CPU, no matter how many simulated multithreads you open, the task cannot be accelerated, because the total computing power of the CPU is that

CPU intensive tasks are configured with as few threads as possible:
General formula: CPU cores + thread pool of 1 thread

IO intensive:

  1. Since IO intensive task threads are not always executing tasks (CPU is not always occupied), configure as many threads as possible, such as CPU cores * 2

  2. IO intensive, that is, the task requires a lot of IO, that is, a lot of blocking.
    Running IO intensive tasks on a single thread will waste a lot of CPU computing power. Therefore, using multithreading in io intensive tasks can greatly speed up program running. Even on a single core CPU, this acceleration mainly takes advantage of the wasted blocking time.

    In IO intensive mode, most threads are blocked, so the number of threads needs to be configured:
    Reference formula: CPU cores / (1-blocking coefficient)

    The blocking coefficient is between 0.8 and 0.9

    For example, 8-core CPU: 8 / (1-0.9) = 80 threads

Thread pool shutdown

Automatic shutdown: two conditions for automatic shutdown of thread pool:

  1. The reference of thread pool is unreachable;

  2. There are no threads in the thread pool;

Deadlock coding and its location

Deadlock: refers to the phenomenon that two or more processes (threads) hold each other's required resources, resulting in waiting for each other.

If there is no external force to interfere, they will not be able to push forward.

Four conditions for Deadlock:

  1. Resource mutual exclusion
  2. Possession without release
  3. No deprivation
  4. Cycle wait

Main causes of Deadlock:

  • Insufficient system resources
  • Improper allocation of resources

Location analysis of deadlock

package com.company.Thread;class ThreadDL implements Runnable{    String lockA;    String lockB;    public ThreadDL(String lockA, String lockB) {        this.lockA = lockA;        this.lockB = lockB;    }    public void run(){        synchronized (lockA){            System.out.println(Thread.currentThread().getName() + "Get A lock");            try {                Thread.sleep(1000);                synchronized (lockB){                    System.out.println(Thread.currentThread().getName() + "Get B lock");                }            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}public class DeadLock {    public static void main(String[] args) {        String A = "lockA";        String B = "lockB";        new Thread(new ThreadDL(A, B),"XXX").start();        new Thread(new ThreadDL(B, A), "YYY").start();    }}

D:\software\java\jdk\bin\java.exe
XXX obtains A lock
YYY obtains A lock

jps: viewing java processes

Jstack: jstack is a stack tracing tool that comes with the Java virtual machine. Jstack is used to print out the Java stack information of a given java process ID or core file or remote debugging service

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-i2fsie0n-163836055883) (Java multithreading. assets/image-20210715161808345.png)]

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-hsam7S3K-1638360355884)(Java multithreading. assets/image-20210715161901813.png)]

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-hdmtwqdp-163836055884) (Java multithreading. assets/image-20210715162146140.png)]

Some applications of threads

Singleton mode

Hungry Han style (load immediately)

/*Hungry Chinese singleton: create an object when the class is loaded* */class FastSingle {    private static volatile FastSingle instance = new FastSingle();    private FastSingle(){}    public FastSingle getInstance(){        return instance;    }}

Lazy (delayed loading)

class Single {    private static volatile Single instance = null;// Instruction rearrangement problem private single() {if (instance! = null) {throws new exception();}} public static single getinstance() {if (instance = = null) {synchronized (single. Class) {if (instance = = null) {instance = new single();}}}         return instance;    }}

Static inner class (deferred load)

/*Static inner class implementation singleton* */class StaticSingle{    /*    Why is the static internal class not loaded when the external class is loaded? effective java says that the static internal class is just written in another class. In fact, it has no subsidiary relationship with the external class. Static inner class: loaded only when used* */    private static class StaticSingleInstance{        private static final StaticSingle instance = new StaticSingle();    }    private StaticSingle(){}    public static StaticSingle getInstance(){        return StaticSingleInstance.instance;    }}

Enumeration type (load now)

/*Enumeration class implementation singleton: 	 zybuluo.com/natsumi/note/692892 enumeration features: 	 The JVM guarantees that enum cannot be reflected and that constructor methods are executed only once* */enum EnumSingle{    INSTANCE; // It can be understood as public static final enumsingle instance; public EnumSingle getInstance(){        return INSTANCE;    }}

Deadlock implementation

package com.company.Thread.DeadLock;public class DeadLock implements Runnable{    String LockA;    String LockB;    public DeadLock(String lockA, String lockB){        this.LockA = lockA;        this.LockB = lockB;    }    @Override    public void run() {        synchronized (this.LockA){            try {                System.out.println(Thread.currentThread().getName() + "Get lock" + this.LockA);                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            synchronized (this.LockB){                System.out.println(Thread.currentThread().getName() + "Eech! No lock post");            }        }    }    public static void main(String[] args) {        String lockA = "Lock A";        String lockB = "Lock B";        Thread thread1 = new Thread(new DeadLock(lockA, lockB));        Thread thread2 = new Thread(new DeadLock(lockB, lockA));        thread1.start();        thread2.start();    }}

Semaphore three threads print ABC X times in turn

package com.company.Thread;import java.util.concurrent.Semaphore;public class SemaphoreABC {    Semaphore semaphoreA = new Semaphore(1);    Semaphore semaphoreB = new Semaphore(0);    Semaphore semaphoreC = new Semaphore(0);    int count;    int total;    public ABC(int all){        this.total = all;        count = 0;    }    public void printABC(){        Thread A = new Thread(new Runnable() {            @Override            public void run() {                while(true) {                    try {                        semaphoreA.acquire();                        if(count == total){                            break;                        }                        System.out.println("A");                        semaphoreB.release();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        Thread B = new Thread(new Runnable() {            @Override            public void run() {                while(true) {                    try {                        semaphoreB.acquire();                        if(count == total){                            break;                        }                        System.out.println("B");                        semaphoreC.release();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        Thread C = new Thread(new Runnable() {            @Override            public void run() {                while(true){                    try {                        semaphoreC.acquire();                        System.out.println("C");                        count++;                        if(count == total){ // Termination condition: semaphorea. Release(); semaphoreB.release();                             break;                        }                         semaphoreA.release();                    }  catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });         A.start();         B.start();         C.start();    }     public static void main(String[] args) {        new SemaphoreABC(3).printABC();    }}

ReentrantLock three threads print ABC in turn

package com.company.Thread.ABC;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ConditionABC {    Lock lock = new ReentrantLock();    Condition conditionA = lock.newCondition();    Condition conditionB = lock.newCondition();    Condition conditionC = lock.newCondition();    int threadFlag = 1;    public void printABC(){        Thread A = new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    try {                        lock.lock();                        while (threadFlag != 1) {                            conditionA.await();                        }                        System.out.println("A");                        threadFlag = 2;                        conditionB.signal();                        lock.unlock();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        Thread B = new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    try {                        lock.lock();                        while (threadFlag != 2) {                            conditionB.await();                        }                        System.out.println("B");                        threadFlag = 3;                        conditionC.signal();                        lock.unlock();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        Thread C = new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    try {                        lock.lock();                        while (threadFlag != 3) {                            conditionC.await();                        }                        System.out.println("C");                        threadFlag = 1;                        conditionA.signal();                        lock.unlock();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        A.start();        B.start();        C.start();    }    public static void main(String[] args) {        new ConditionABC().printABC();    }}

Condition: producer consumer problem

package com.company.Thread.PAndC;import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class PAndC {    Queue<String> source;    int count;    Lock lock;    Condition condition;    public PAndC(Queue<String> source, int count) {        this.source = source;        this.count = count;        this.lock = new ReentrantLock();        condition = this.lock.newCondition();    }    public void producrMethod(){        while (true) {            try {                lock.lock();                while (source.size() == count) {                    condition.await();                }                source.offer("resources");                System.out.println(Thread.currentThread().getName() + " producer: " + source.size() );                condition.signal();                lock.unlock();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public void consumerMethod(){        while (true) {            try {                lock.lock();                while (source.size() == 0) {                    condition.await();                }                source.poll();                System.out.println(Thread.currentThread().getName() + " consumer: " + source.size() );                condition.signal();                lock.unlock();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public void GenAndCon(){        Thread producer = new Thread(new Runnable() {            @Override            public void run() {                producrMethod();            }        });        Thread producer2  = new Thread(new Runnable() {            @Override            public void run() {                producrMethod();            }        });        Thread consumer = new Thread(new Runnable() {            @Override            public void run() {                consumerMethod();            }        });        producer.start();        producer2.start();        consumer.start();    }    public static void main(String[] args) {        new PAndC(new LinkedList<>(), 5).GenAndCon();    }}

Semaphore: producer consumer issues

package com.company.Thread.PAndC;import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.Semaphore;public class PCSemaphore {    Queue<String> source;    int count;    Semaphore semaphoreP; // Control producer Semaphore semaphoreC// Control consumer Semaphore mutex// Mutex: control the mutex access of source public pcsemaphore (queue < string > source, int count) {this.source = source; this.count = count; / / the number of semaphorep that can be produced (indicating the number of buffers available). Reduce the number of permissions by calling acquire by the producer semaphorep = new semaphore (5) ; / / the quantity that semaphorec can consume. Increase the number of permissions by calling release by the producer semaphorec = new semaphore (0); mutex = new semaphore (1);} public void producrmethod() {while (true) {try {semaphorep. Acquire(); mutex. Acquire(); source. Offer ("resource") ; System.out.println(Thread.currentThread().getName() + "producer:" + source.size()); mutex. Release(); semaphorec. Release();} catch (interruptedexception E) {e.printstacktrace();}}} public void consumermethod() {while (true) {try {semaphorec. Acquire(); mutex. Acquire(); source. Poll(); mutex. Release(); System.out.println(Thread.currentThread().getName() + "consumer:" + source.size()) ; / / the producer calls release to increase the quantity that can be consumed semaphorep. Release();} catch (interruptedexception E) {e.printstacktrace();}}} public void genandcon() {thread producer = new thread (New runnable() {@ override public void run())  {                producrMethod();            }        });        Thread producer2  = new Thread(new Runnable() {            @Override            public void run() {                producrMethod();            }        });        Thread consumer = new Thread(new Runnable() {            @Override            public void run()  {                consumerMethod();            }        });        producer.start();        producer2.start();        consumer.start();    }    public static void main(String[] args) {        new PCSemaphore(new LinkedList<>(), 5).GenAndCon();    }}

wait() and notifyAll(): the sum of producer consumption

consumer

package com.company.Thread.ProducerAndConsumer;import java.util.List;import java.util.concurrent.TimeUnit;public class Consumer implements Runnable{    /**     * Product container     */    private final List<Integer> container;    public Consumer(List<Integer> container) {        this.container = container;    }    /**     * Consumer products     */    private void consume() throws InterruptedException {        // System. Out. Println ("consume not in"); synchronized (container) {/ / system. Out. Println ("consume in"); while (container. Isempty()) {system. Out. Println ("... Container is empty, pause consumption..."); container. Wait();} integer p = container. Remove (0) ; / / simulate the consumption of a product in 1 second timeunit.milliseconds.sleep (1000); system.out.println ("consumer product:" + P); container. Notifyall();}} @ override public void run() {while (true) {try {consume();} catch (interruptedexception E) {                e.printStackTrace();                System.out.println("consume error");            }        }    }}

producer

package com.company.Thread.ProducerAndConsumer;import java.util.List;import java.util.Random;import java.util.concurrent.TimeUnit;public class Producer implements Runnable {    /**     * Product container     */    private final List<Integer> container;    public Producer(List<Integer> container) {        this.container = container;    }    /**     * Producer production method * * @ throws InterruptedException     */    private void produce() throws InterruptedException {        //Product container capacity int capacity = 5// System.out.println("   produce  not in ");         Synchronized (container) {/ / system. Out. Println ("produce in"); / / when the container is full, suspend production while (container. Size() = = capacity) {system. Out. Println ("... Container is full, suspend production..."); container. Wait();} random random = new random() ; int p = random. Nextint (50); / / simulate the production of a product in 1 second timeunit. Milliseconds. Sleep (1000); system. Out. Println ("production product:" + P); container. Add (P); container. Notifyall();}} @ override public void run() {while (true) {try {                produce();            } catch (InterruptedException e) {                e.printStackTrace();                System.out.println("produce error");            }        }    }}

call

package com.company.Thread.ProducerAndConsumer;import java.util.ArrayList;import java.util.List;public class Test {    public static void main(String[] args) {        List<Integer> container = new ArrayList<>();        Thread producer = new Thread(new Producer(container));        Thread producer2 = new Thread(new Producer(container));        Thread producer3 = new Thread(new Producer(container));        Thread consumer = new Thread(new Consumer(container));        Thread consumer2 = new Thread(new Consumer(container));        producer.start();        producer2.start();        producer3.start();        consumer.start();        consumer2.start();    }}

JVM

JVM memory

Garbage collection for JVM

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-pexphbkh-163836055885) (Java multithreading. assets/image-20210715215310709.png)]

Java class loading mechanism?

  1. Load: load the class through the parental delegation mechanism
  2. link
    1. Validation: syntax error checking
    2. Preparation: memory allocation, initialization 0
    3. Resolution: character reference - > direct reference
  3. Initialization: clinit method (static method block and so on)

What happens after a new object in Java?

  1. Class loading
  2. memory allocation
  3. Initialize 0
  4. Set object header
  5. Initial constructor and so on

Scope of GC:

Heap and method area

How to judge whether garbage can be recycled?

  • Reference count

  • Accessibility analysis

Which objects can be used as GC roots?

  1. Objects in virtual machine stack
  2. Object of local method stack
  3. Object of static attribute in method area, reference in constant pool
  4. JVM internal call (Class object, resident Exception, ClassLoader)
  5. JMXBean reflecting the internal situation of the JVM and callback of the JVMTI
  6. Objects held by Synchronized

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-mfnnvt52-163836055885) (Java multithreading. assets/image-20210715170735015.png)]

How to perform JVM tuning and parameter configuration:

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-JMxy0mZj-1638360355886)(Java multithreading. assets/image-20210715171539937.png)]

JVM parameter type

  • Standard configuration parameters

  • x parameter

    • -Xint interpretation execution
    • -Xcomp is compiled into native code the first time it is used
    • -Xmixed mixed mode

    The difference between compilation and interpretation

  • XX parameter

    • Boolean type (+ means to turn on the corresponding parameter function, - means to turn off the corresponding parameter function: - XX: +PrintGCDetails)
    • K - V type (set some parameter values, such as meta space size: - XX:MetaspaceSize = 128m)
    • other:
      • -Xms and - Xmx
      • -Xms is equivalent to - XX:InitialHeapSize (initial heap memory, 1 / 64)
      • -Xmx is equivalent to - XX:MaxheapSize (maximum heap memory, 1 / 4)

    It is used to set specific parameters, which are divided into two types: + / - boolean type and KV key value type

jinfo: check whether some JVM parameters corresponding to the running Java process are enabled

jinfo -flag specific parameter java process number

jinfo -flags java process number

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-jaNp4oHu-1638360355886)(Java multithreading. assets/image-20210715172319162.png)]

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-kbrtjzoa-163836055887) (Java multithreading. assets/image-20210715172802340.png)]

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (IMG voytcboh-163836055887) (Java multithreading. assets/image-20210715173526404.png)]

java -XX:+PrintFlagsInitial / / get JVM initial parameters

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-eb1ojna-163836055887) (Java multithreading. assets/image-20210715174821979.png)]

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-6wg06nl4-163836055888) (Java multithreading. assets/image-20210715174407285.png)]

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-oqvjzms5-163836055888) (Java multithreading. assets/image-20210715184740859.png)]

java -XX:+PrintFlagsFinal / / get the modified parameters of the JVM

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-XetCHBig-1638360355889)(Java multithreading. assets/image-20210715185033624.png)]

-20: + printcommandlineflags: print command line parameters

Basic configuration commonly used by JVM

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-blcxlxsi-163836055890) (Java multithreading. assets/image-20210715192135109.png)]

-Xms is equivalent to - XX:InitialHeapSize. Set the initial heap memory size, which is 1 / 64 of the default physical memory

-Xmx is equivalent to - XX:MaxHeapSie sets the maximum heap memory size, which is 1 / 4 of the default physical memory

-Xss is equivalent to - XX: threadsacksize. Set the size of the thread stack. The default is 512k - 1024k

-Xmn set younger generation size

-20: Metaspacesize sets the size of the meta space (by default, the meta space is limited only by local memory)

With default size

-20: + useserialgc set serial garbage collection

-20: + useparallelgc set parallel garbage collection

-20: Printgcdetails print GC details

-20: Survivorratio sets the scale of eden, S0 and S1 spaces. The default is 8:1:1; If - XX:SurvivorRatio=4 is set, it will be 4:1:1. Here is the eden scale

-20: Newratio sets the ratio of the young generation to the old generation. If - XX:NewRatio=2, the new generation: old age = 1:2

If - XX:NewRatio=4, then Cenozoic: old age = 1:4 (default 1:2)

-20: Maxtenuringthreshold sets the maximum age of garbage. If it is set to 0, the younger generation objects directly enter the older generation without passing through the Survivor area. For applications with more elderly generations, efficiency can be improved. If this value is set to a large value, the younger generation objects will be copied many times in the Survivor area, which can increase the survival time of the younger generation and the probability of being recycled in the younger generation.

java -XX:PrintGCDetails

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-pssbkcyb-163836055890) (Java multithreading. assets/image-20210715193738653.png)]

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-xoj19udw-163836055891) (Java multithreading. assets/image-20210715193942551.png)]

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-zglnxvkb-163836055891) (Java multithreading. assets/image-20210715193646631.png)]

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-o2gcvbnv-163836055892) (Java multithreading. assets/image-20210715194004964.png)]

https://docs.oracle.com/javase/8/docs/index.html

Reference problem (strong, soft, weak, virtual, reference queue)

Reference hierarchy

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-nxtl5pyk-163836055892) (Java multithreading. assets/image-20210715205953295.png)]

Four references and reference queues

Strong reference

**GC angle: * * even if OOM occurs, the object will not be recycled

**Scenario: * * is our most common reference. Assign an object to a reference variable, which is a strong reference. When an object is strongly referenced, it is reachable and will not be recycled by GC.

Strong references are also one of the causes of memory leaks

Soft reference

**GC perspective: * * if the memory is enough, it will not be recycled; if not enough, it will be recycled

**Scenario: * * it will be used in memory sensitive programs, such as cache

Weak reference

**GC perspective: * * if the referenced object has a strong reference, it will not be recycled. On the contrary, if the referenced object does not have a strong reference, it will be recycled

Scenario: the key of ThreadLocal is the weak reference used

Virtual reference

As the name suggests, it is virtual. Unlike other references, virtual references do not determine the life cycle of objects.
**From the perspective of GC: * * if an object only holds virtual references, it may be recycled by the garbage collector at any time like it does not have any references. It cannot be used alone or access objects through it. Virtual references must be used in conjunction with reference queues.
**Scenario: * * the main function of virtual reference is to track the garbage collection status of objects. It only provides a mechanism to ensure that the object does something after it is finalize d.
The get method of phantom reference always returns null, so the corresponding reference object cannot be accessed. Its significance is that an object has entered the finalization stage and can be recycled by gc to realize more flexible recycling operations than the finalization mechanism.

In other words, the only purpose of setting reference association is to receive a system notification or add further processing when the object is recycled by the collector.

Reference queue

When GC is referenced in Java, it will be saved in the reference queue ReferenceQueue during this period (before GC).

**Function: * * we want to notify the user thread when an object is gc dropped. When additional processing is performed, we need to use the reference queue. ReferenceQueue is such an object. When an obj is gc removed, its corresponding wrapper class, ref object, will be put into the queue. We can get the corresponding object information from the queue and carry out additional processing at the same time. Such as reverse operation, data cleaning, etc.

Therefore, virtual references and reference queues are often used together

Introduction to relevant scenes

Soft reference scenario

If an application needs to read a large number of local pictures:

  • If the picture is read from the hard disk every time, it will seriously affect the performance,

  • If all of them are loaded into memory at one time, it may cause memory overflow.

This problem can be solved by using soft reference:
The design idea is to use a HashMap to save the mapping relationship between the path of the picture and the soft reference associated with the corresponding picture object. When the memory is insufficient, the JVM will automatically reclaim the space occupied by these cached picture objects, so as to effectively avoid the problem of OOM.

Map<String, SoftReference<Bitmap>>imageCache = new HashMap<String, SoftReference<Bitmap>>();

Do you know WeakHashMap?

The key of WeakHashMap is a weak reference

Citation summary

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-zlh446tu-163836055893) (Java multithreading. assets/image-20210715215206682.png)]

Common OOM errors

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-c5vx5mcf-163836055893) (Java multithreading. assets/image-20210715220008989.png)]

NullPointerException

  • StackOverflowError stack space overflow
  • OutOfMemoryError: Java heap space is out of heap space
  • OutOfMemoryError: Metaspace
  • OutOfMemoryError: Direct buffer memory
  • OutOfMemoryError: GC overhead limit exceeded
  • OutOfMemoryError: unable to create new native thread

StackOverflowError

Java heap space

GC overhead limit exceeded

OutOfMemoryError: GC overhead limit exceeded

Outofmemoyerror will be thrown when GC recovery time is too long.

The definition of too long is that more than 98% of the time is spent on GC and less than 2% of the heap memory is recycled. It will be thrown only under the extreme condition that less than 2% of the heap memory is recycled for consecutive GC times.

What happens if the GC overhead limit error is not thrown? That is, the memory cleaned by GC will soon fill up again, forcing GC to execute again. This will form a vicious circle. The CPU utilization rate has always been 100%, but GC has no results

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-pijxemxa-163836055894) (Java multithreading. assets/image-20210715221237896.png)]

Direct buffer memory

OutOfMemoryError: Direct buffer memory

The size of meta space is limited by local memory;

Cause:
Writing NIO programs often use ByteBuffer to read or write data. This is an I/0 method based on channel and buffer. It can directly allocate off heap memory using the Native function library, and then operate through a DirectByteBuffer object stored in the Java heap as a reference to this memory. This can significantly improve performance in some scenarios because it avoids copying data back and forth between the Java heap and the Native heap.

***ByteBuffer.allocate(capability) * * * the first way is to divide the JVM heap memory, which belongs to the jurisdiction of GC. Because it needs to be copied, the speed is relatively slow

***ByteBuffer.allocateDirect(capability) * * * the second method is to allocate OS local memory, which is not under the jurisdiction of GC. Since memory copy is not required, the speed is relatively fast

However, if local memory is allocated continuously and heap memory is rarely used, the JVM does not need to execute GC and DirectByteBuffer objects will not be recycled. At this time, heap memory is sufficient, but local memory may have been used up. OutOfMemoryError will appear if you try to allocate local memory again. The program crashed directly.

unable to create new native thread

OutOfMemoryError: unable to create new native thread

Cause of rescue guidance:

  1. Your application has created too many threads. An application has created multiple threads, exceeding the system load limit
  2. Your server does not allow your application to create so many threads. By default, the Linux system allows a single process to create 1024 threads. If your application creates more than this number, it will report java.lang.OutOfMemoryError: unable to create new native thread

terms of settlement:

  1. Find ways to reduce the number of threads created in your application and analyze whether the application really needs to create so many threads. If not, change the code to minimize the number of threads
  2. For some applications, a lot of money needs to be created, which is far beyond the default limit of 1024 threads of the Linux system. You can modify the Linux server configuration and expand the default limit of inux

Simply put, there are too many threads created

Metaspace

OutOfMemoryError: Metaspace

Java 8 and later versions enable the month's etaface to replace the permanent generation.
Metaspace is the implementation of method area in Hotspot. The biggest difference between Metaspace and persistent generation is that Metaspace does not exist in virtual machine memory, but uses local memory

That is, in java8, the class metadata (the virtual machines internal presentation of Java class) is stored in a memory called Metaspace proactive memory

After java8, the permanent generation is replaced by the meta space, which stores the following information:

  • virtual machine
  • Loaded class information
  • Runtime Constant Pool
  • Static variable
  • Just in time compiled code

Simulating Metaspace space overflow, we constantly generate classes to fill the Metaspace, and the space occupied by the classes will always exceed the space specified by the Metaspace

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-nCC9fhuB-1638360355894)(Java multithreading. assets/image-20210716094624060.png)]

garbage collection

The object is dead

  1. Reference counting method

  2. Accessibility analysis

Garbage collection algorithm

  1. Mark clear
  2. copy
  3. Marking arrangement
  4. Generation recycling

Garbage collector

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-rmqrokmy-163836055895) (Java multithreading. assets/image-20210716102205386.png)]

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-3ENBBKnM-1638360355895)(Java multithreading. assets/image-20210716103246921.png)]

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-xBwjxAcN-1638360355896)(Java multithreading. assets/image-20210716103617700.png)]

View the default garbage collector

java -XX:+PrintCommandLineFlags -version

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (IMG ootetseu-163836055897) (Java multithreading. assets/image-20210716102125394.png)]

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-7g8k5xin-163836055897) (Java multithreading. Assets / image-202107161024526. PNG)]

Client / Server

Scope of application:

  • You only need to master the Server mode, and the Client mode is basically useless

Operating system:

  • The 32-bit Window operating system uses the JVM mode of the Client by default regardless of the hardware
  • 32-bit other operating systems, 2G memory, more than 2 CPUs at the same time, use Server mode, lower than this configuration or Client mode
  • 64 bit only server mode

SerialGC (Cenozoic)

New generation serial, old age serial

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-A3d20Iv1-1638360355898)(Java multithreading. assets/image-20210716103552015.png)]

ParNew (Cenozoic)

New generation parallel, old age serial

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-84ptsln8-163836055899) (Java multithreading. assets/image-20210716104258112.png)]

Parallel Scavenge

The new generation is parallel, and the old era is also parallel

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-wu8gcjzv-163836055899) (Java multithreading. assets/image-20210716104310501.png)]

Throughput:

Similar to the ParNew garbage collector, which focuses more on throughput, throughput = user thread running time / (user thread running time + GC running time), which means efficient use of CPU time. It is mostly used for tasks that operate in the background without too much interaction

Adaptive adjustment strategy:

It is also an important difference between the parallelscape collector and the ParNew collector. (adaptive adjustment strategy: the virtual opportunity collects performance monitoring information according to the current system operation, and dynamically adjusts these parameters to provide the most appropriate pause time (- XX:MaxGCPauseMillis) or maximum throughput.

Common JVM parameters:

-20: + useparallelgc or - XX: + useparalleloldgc (can activate each other) uses the Parallel Scanvenge collector

When this parameter is enabled, the new generation uses the copy algorithm and the old generation uses the mark sort algorithm

One more word:

-20: Parallelgcthreads = the number N indicates how many GC threads are started

cpu>8 N=5/8
CPU < 8 N = actual number

Concurrent Mark Sweep

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-HLg1mOoo-1638360355900)(Java multithreading. assets/image-20210716105953278.png)]

  1. Because of concurrency, CMS will increase the occupation of heap memory when collecting and applying threads,

In other words, CMS must complete garbage collection before the old generation heap memory is exhausted. Otherwise, when CMS collection fails, the guarantee mechanism will be triggered, and the serial old generation collector will perform a GC in the form of STW, resulting in a large pause time

  1. Mark clearing method, resulting in memory fragmentation

Garbage First

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-ragkg4e2-163836055900) (Java multithreading. assets/image-20210716111623646.png)]

  • Like the CMS collector, it can execute concurrently with the application thread.
  • It's faster to clean up free space.
  • More time is needed to predict GC pause times.
  • You don't want to sacrifice a lot of throughput performance.
  • No larger Java Heap is required.

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-1oznxw2j-163836055901) (Java multithreading. assets/image-20210716112712000.png)]

The design goal of G1 collector is to replace CMS collector. Compared with CMS, it performs better in the following aspects:

  1. G1 is a garbage collector with a memory defragmentation process, which will not produce a lot of memory fragments.
  2. G1's Stop The World(STW) is more controllable; G1 adds a prediction mechanism to the pause time, and users can specify the desired pause time.

Although CMS garbage collector reduces the running time of suspended applications, it still has the problem of memory fragmentation. Therefore, in order to remove the problem of memory fragmentation and retain the advantage of low pause time of CMS garbage collector, JAVA7 released a new garbage collector - G1 garbage collector.

G1 was only available in jdk1.7u4 in 2012. oracle officially plans to turn G1 into the default garbage collector in JDK9 to replace CMS.

It is a server-side application-oriented collector, which is mainly used in the environment of multi CPU and large memory server, greatly reducing the pause time of garbage collection, comprehensively improving the performance of the server and gradually replacing CMS

  1. Memory is divided into sub regions
  2. The overall label sorting algorithm and local replication algorithm will not produce memory fragments
  3. Physically, there is no distinction between the young generation and the old generation, but logically, there is the concept of generation (that is, the sub regions of different generations are not physically continuous)
  4. Pause time can be precisely controlled
  5. Order: initial tag - Concurrent tag - Final tag - filter recycle

How to tune JVM + GC + SpringBoot

  1. IDEA developed microservice project

  2. maven clean package

  3. When the microservice is required to start, configure the tuning parameters of our JVM/GC at the same time

    1. Internal startup:

      [the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-146Z87BR-1638360355901)(Java multithreading. assets/image-20210716113435014.png)]

    2. External start:

      [the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-r1qhvcdp-163836055901) (Java multithreading. assets/image-20210716113402898.png)]

summary

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-wW66f4GS-1638360355902)(Java multithreading. assets/image-20210716110439141.png)]

Java tools

jps

jstack

jinfo

Tags: Java

Posted on Wed, 01 Dec 2021 20:31:08 -0500 by vidhu