What are processes and threads

  • Process: A process is an in-memory application, such as our JAR package, or a game, which on Linux or Windows is a process
  • Thread: A thread is an execution process in a process. A process can have multiple threads. For example, in the game Chicken, each player is a thread and the thread belongs to the process

Implementation of threads in Java

There are two ways to create a thread in Java

  • inheritanceThread
  • implementationRunnable interface

2.1 inheritanceTheadclass

public class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() +" "+i); } } } public class MyThreadTest { public static void main(String[] args) { MyThread th1 = new MyThread(); MyThread th2 = new MyThread(); th1.start(); th2.start(); }}Copy the code

Get the output

Thread-0 0
Thread-1 0
Thread-0 1
Thread-1 1
Thread-1 2
Thread-1 3
Thread-0 2
Thread-0 3
Thread-1 4
Thread-0 4
Copy the code

2.2 implementationRunnable

public class MyThread2 implements Runnable { @Override public void run() { for (int i = 0; i < 10; I ++) {system.out.println (thread.currentThread ().getName()+" currentThread "+ I); } } } public class MyThreadTest { public static void main(String[] args) { MyThread2 myThread1 = new MyThread2(); MyThread2 myThread2 = new MyThread2(); Thread thread = new Thread(myThread1); Thread thread2 = new Thread(myThread2); thread.start();; thread2.start(); }}Copy the code
Thread-0:0 Thread-0:1 Thread-1:1 Thread-0:2 Thread-1:2 Thread-0:3 Thread-0:4 The current value of thread-1 is 3 thread-1 Is 4 Thread-1 is 5 thread-0 The current value of thread-1 is 6 thread-0 the current value of thread-1 is 7Copy the code

2.3 pay attention to the point

Start does not immediately run the thread. Instead, start puts the thread in an executable state and runs the run method whenever the thread has a chance to execute. Each Thread has its own name, which can be obtained by thread.currentThread ().getName()

3 Switching thread status

3.1 Five States

  • new: The thread object has been created, but has not yet been calledstartmethods
  • Can be run: There are two possibilities:
    • The thread has already calledstartMethod, but the calling program has not yet selected the thread and allowed
    • A thread returns from a blocked or dormant, wait state after it runsCan be run
  • run: The state of a thread when the thread scheduler selects a thread from the runnable pool as the current thread. This is also the only way a thread can get into a running state.
  • Wait/block/sleep: A thread is eligible to run, but due to some external force, it suspends and becomes runnable when certain conditions are met
  • deathThe task is dead if called on a dead threadstartWill throw an exception

3.2 Thread state machines

3.3 Several ways to block thread permission

  • sleepmethodsThread.sleep(long millis)Thread.sleep(long millis, int nanos)Force a running thread to sleep. When sleep time reaches, the thread returns to the runnable state, but it is not run directly. This method is static and can only control the currently running thread.

-yield This method can suspend the current running thread and execute other threads. In practice, however, yield does not guarantee that a thread will yield. Even if a thread yields, it will be selected again by the thread schedule

  • joinNon-static methods allow one thread B to join the tail of another thread A. A cannot work until B is finished

4 Thread synchronization

Thread synchronization is to prevent the same variable from being accessed by multiple threads at the same time, resulting in unexpected consequences. In order to ensure thread safety, we can adopt the synchronization lock mechanism

4.1 Mechanism of Synchronous Lock

Every object in Java can be used as a lock

  1. The normal synchronization method locks the instance object
  2. Synchronized code blocks that lock objects in parentheses
  3. Statically synchronized methods that lock the current class

When a thread accesses a block of synchronized code or method, it needs to acquire the lock

  • The LOCKING of synchronized blocks depends on montitorEnter and monitorExit. The JVM needs to ensure that each synchronized block has a corresponding Enter and exit. Enter indicates that the thread holds the synchronized block, i.e. acquires the lock on the object, and exit indicates that the synchronized block is abandoned
  • Methods rely on the ACC_SYNCHRONIZED implementation of method modifiers

4.2 object head

Object headers in Java are the basis for implementing synchronous locking, as we’ll briefly look at below. The object header consists of two parts of data, Mark Word and Klass Point.

The mark word is used to store data about objects running, including GC generation age, lock status flags, hashcode, thread-held locks, etc. It is a non-fixed data structure in order to store the most data in the smallest amount of memory. Monitor is a synchronization mechanism and is often described as an object. An Owner field in Monitor holds a unique identifier for the thread that owns the lock, indicating that the lock is occupied by that thread. Its structure is as follows:

4.4 lock optimization

4.4.1 the spin lock

Spinlocks were introduced to deal with frequent CPU switching (and because objects are locked for a relatively short period of time). The idea of a spinlock is to make a thread wait a little longer (through a meaningless loop) rather than suspend immediately.

  • Advantages: No overhead associated with thread switching
  • Disadvantages: If the thread holding the lock is not released for a period of time, the spin thread will consume processing resources for nothing. The spin wait time (number of spins) must be limited

4.4.2 Adapt to spin locks

Spin locks can artificially control the number of spins, but if we just finished spinning and entered the suspended state, it would be embarrassing to get out of the manhole. Then adaptive spin locks came into being. The number of spins is no longer fixed. It is determined by the last time the same lock was released and the state of the previous holder. If the thread spins successfully, the number of spins will increase next time (if it succeeded last time, it will succeed this time too). If the spin fails, the next spin will be lower.

4.4.3 lock elimination

The JVM detects that there is no possibility of a shared data race, which is when the JVM removes these synchronized locks.

4.4.4 lock coarsening

Is lock granularity as small as possible? Most of the time I agree, but a series of lock unlocks can lead to frequent CPU switching. There is a lot of unnecessary performance loss. Locking coarsening is a series of locking, releasing chains into one large lock

4.4.5 Lightweight Locks

When biased locks are closed or multiple threads compete for biased locks, biased locks are upgraded to lightweight locks in order to reduce the performance cost of traditional heavyweight locks using operating system mutex.

4.4.5.1 To obtain a Lightweight lock, do as follows
  1. Checks whether the current object is unlocked. The JVM creates a Lock Record from the current thread’s stack frame and stores the current object’s Mark Word into the Lock Record. Otherwise, go to Step 3
  2. The JVM uses CAS to try to place objectsMark wordUpdate to pointLock RecordIf yes, the lightweight lock is obtained. Otherwise, go to Step 3
  3. Judge objectMark WordIf yes, the current thread already holds the lightweight lock, and enters the synchronous code block execution. Otherwise, the object lock has been preempted by other threads, and the lightweight lock expands the minor heavyweight lock
4.4.5.2 Releasing lightweight Locks
  1. Remove lightweight locks inLock RecordData stored in
  2. CAS attempts to replace the retrieved data with the object’sMark WordIf yes, the release is successful. If no, go to Step 3
  3. If this fails, another thread is trying to acquire the lock and needs to invoke the other thread at the lock release

The main rationale for lightweight locks is that for the vast majority of locks, there is no contest for their entire life cycle. Lightweight locks perform slower than heavier-weight locks in high concurrency cases (due to the introduction of CAS)

4.4.6 biased locking

Biased locking minimizes unnecessary CAS operations without multithreaded contention

4.6.1 acquiring a lock
  1. Detection objectMark WordWhether it is in the biased state, biased to lock 1, lock identification bit 01;
  2. If the thread ID is the ID of the current thread, go to Step 5. Otherwise, go to Step 3
  3. If thread ID! = current thread ID, then CAS spins the object’sMark WordIs updated to the ID of the current thread. If the operation fails, go to Step 4
  4. The CAS failed to compete for the lock, indicating that there is a multi-thread contention. The competing thread is suspended and upgraded to a lightweight lock
  5. Execute sync code

4.5 Precautions

Each Java object header has a lock. When running a non-static synchronized modified method or a synchronized code block, the thread automatically acquires the lock on the current object, because an object has only one lock. Until thread A holds the lock and releases it, no other thread can hold it. Here is a summary of some key locking and synchronization points

  1. There is only one lock per object, by synchronizedModified non-static methods or synchronized code blocks can run only one thread at a time.
  2. An object can have both synchronous and non-synchronous methods, and non-synchronous methods do not generate contention and lock hogs
  3. When a thread sleeps, its lock is not released
  4. A thread can hold multiple synchronization locks for different objects at the same time
  5. Static methods lock synchronouslyclassCompetition can occur even between different object instances