“This is the sixth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Thread status and basic operations

1. Create a thread

  • Override the run method by inheriting Thread
  • By implementing the Runnable interface
  • By implementing the Callable interface
Thread Thread = new Thread(){@override public void run() {log.e (TAG, "Thread start"); super.run(); }}; thread.start(); Thread1 = new Thread(new Runnable() {@override public void run() {log.e (TAG, "thread1 start"); }}); thread1.start(); / / implementation Callable interface ExecutorService service = Executors. NewCachedThreadPool (); Future<String> future = service.submit(new Callable<String>() { @Override public String call() throws Exception { Log.e(TAG, "Callable start"); return "finish"; }}); try { String result = future.get(); Log.e(TAG, "Callable result is " + result); } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); }Copy the code

2. Thread status switchover

The state name instructions
NEW In the initial state, the thread is built, but the start method has not been called
RUNNABLE Running state, Java threads refer to the ready and running states of the operating system as running
BLOCKED Blocked state, indicating that the thread is blocked on the lock
WAITING Wait state, which indicates that the thread has entered the wait state, which indicates that the current thread needs to wait for other threads to do the following specific action (notification or interrupt)
TIME_WAITING A timeout wait state that, unlike WAITING, can return at a specified time
TERMINATED Terminated status: indicates that the current thread has finished executing

You may be asked in an interview to call start twice or something, but knowing the state of the thread is an easy answer.

3. Basic operations of threads

interrupt

join

If A thread instance A executes threadb.join (), it means that the current threadA waits for threadB to terminate before threadA continues.

sleep

Sleep () wait ()

1. Sleep is a static method of Thread, and wait is an instance method of Object

2. The wait method must be called within a synchronized method or block, i.e. the object lock must have been acquired. Sleep does not have this restriction. In addition, the wait method releases the object lock of the companion, forcing the thread to wait in the waiting pool for the next resource acquisition, while the sleep method only releases the CPU and does not release the object lock

3. If again after sleep in sleep time to obtain the CPU time slice will continue, and wait method have to wait for the Object. Notify/Object notifyAll notification, will leave the waiting pool.

yield

The current thread cedes the CPU to another thread. If none is met, yield does not apply.

4. Daemon threads

synchronized

classification The specific classification The locked object Pseudo code
methods Instance methods Class public synchronized void method() {}
A static method Class object public static synchronized void method() {}
The code block Instance objects Class synchronized(this){}
Class object Class object synchronized(King.class){}
Instance Object Object Instance Object Object Object lock = new Object(); synchronized(lock){}

Note: if a class object is locked, even if new multiple instances of the object, but they still belong to the same class, will still be locked, i.e., synchronization between threads is guaranteed.

CAS operations (compare and swap)

The CAS operation contains three values: V Actual value stored in the memory address, O expected value (old value), and N updated value. When V and O phase at the same time, also is the same old value and actual value in the memory, suggests that the value is not modified, that is, the old value O is currently the latest value, natural new value can be assigned to V, on the other hand, V and O, indicates that the value has been other threads to mend, so can’t to assign a new value N V, return to V. When multiple threads manipulate a variable using CAS, only one thread will succeed and update successfully, and the rest will fail. A thread that fails will try again, or you can choose to suspend it.

volatile

1. Write the data in the current processor cache line back to the system memory

2. This write back operation invalidates the data cached by other cpus

3. When the processor finds that the local cache is invalid, it re-reads the variable data from the memory to obtain the latest value.

Volatile uses this mechanism to enable each thread to obtain the latest value of the variable.

final

variable

Final member variable

Class variables can be assigned initial values directly when they are declared or assigned values in static code blocks.

Instance variables can be assigned initial values at variable declaration time, in non-static code blocks, and in constructors.

Final local variable

Final local variables are explicitly initialized by the programmer. If they are already initialized, they cannot be changed again. If a final variable is not initialized, it can be assigned, only once.

Note: When final modifies a primitive variable, the primitive data type cannot be reassigned. For a reference type variable, it is just a reference, and final only guarantees that the address referenced by the reference type will not change, that is, the object will always be referenced, but the object property can be changed.

methods

A method of a parent class is final and cannot be overridden by subclasses

Methods that are modified by final can be overridden

class

When a class is final, that class cannot be inherited by subclasses.

Final in multithreading

Don’t understand,

Introduction to three major Attributes

atomic

An operation is uninterruptible, and either all of them succeed or all of them fail, with a sense of life or death.

int a = 10; // a++; Int b = a; int b = a; int b = a; a = a + 1;Copy the code

Atomic operations in the Java memory model:

Lock: Acts on variables in main memory to identify a variable as a thread-exclusive state

Unlock: A variable that acts on main memory, freeing a variable that is locked and can be locked by another thread

Read: a variable that operates on main memory, transferring the value of a variable from main memory to the thread’s working memory to facilitate load operations

Load: Applies to variables in working memory, putting the values of the variables obtained from main memory by the read operation into a copy of the variables in working memory

Use: Applies to a variable in working memory, passing the value of a variable in working memory to the execution engine. This operation is performed whenever the virtual machine reaches a bytecode instruction that needs to use the value of the variable

Assign: Applies to a variable in working memory, assigning a value received from the execution engine to the variable

Store: variable applied to working memory that passes the value of a variable in working memory to main memory for subsequent write operations

Write: a variable that operates on main memory. It puts the value of a variable in main memory that the store operation obtains from working memory

order

Synchronized semantics indicates that a lock can be acquired by only one thread at a time. When the lock is occupied, other threads can only wait. Therefore, synchronized semantics require threads to perform only “serially” when accessing and reading shared variables, and thus synchronized is ordered.

In the Java memory model, the compiler and processor reorder instructions for performance optimization. To sum up: if the thread is observed, all operations are ordered, if the thread is observed, all operations are disordered.

Volatile includes the semantics that prohibit instruction reordering and is ordered

visibility

When one thread makes a change to a shared variable, other threads can immediately get the change.

Synchronized Obtains the latest value of a shared variable from the main memory. When releasing the lock, the variable is synchronized to the main memory.

Volatile is visible

Atomic operation class

The atomic package under Java.util.Concurrent provides a series of simple, high-performance, and thread-safe classes to update primitive variables, array elements, reference types, and field types in objects. The classes in the Atomic package implement atomic update data using an optimistic locking strategy, which in Java is implemented using CAS operations.

The main problems of synchronized are: performance problems caused by thread blocking and wakeup lock in the case of thread contention, which is a kind of mutually exclusive synchronization;

The main difference is that CAS does not arbitrarily suspend a thread, and attempts to do so when the CAS operation fails, rather than time-consuming suspends and wakes it up.

Atomic update base type

Atomic provides utility classes for atomic update base types:

  • AtomicInteger
  • AtomicBoolean
  • AtomicLong

Take AtomicInteger as an example to summarize common methods:

AddAndGet (int data) : atomically adds the input value to the original value and returns the final result

IncrementAndGet () : Atomically increments the original value in the instance to +1 and returns the final result

3. GetAndSet (int newValue) : updates the value in the instance to the newValue

4. GetAndIncrement () : Increments the original value and returns the original value

/**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
public final int getAndIncrement() {
    return U.getAndAddInt(this, VALUE, 1);
}
Copy the code

The Unsafe class provides CAS operations, such as compareAndSwapInt and compareAndSwapLong.

Atomic update array type

  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray

To summarize the common methods with AtomicIntegerArray:

1.addAndGet(int i, int delta)

GetAndIncrement (int I) increment (int I)

3.compareAndSet(int i, int expect, int update)

Atomic update reference types

AtomicReference: Atomic update reference type

AtomicReferenceFieldUpdater: atomic updates a reference type in the field

AtomicMarkableReference: Atom updates reference types with marker bits

AtomicReference<User> userAtomicReference = new AtomicReference<>();
userAtomicReference.set(u1);

User user = userAtomicReference.getAndSet(u2);
Log.e(TAG, "age = " + user.getAge());

User user2 = userAtomicReference.get();
Log.e(TAG, "age = " + user2.getAge());
Copy the code

Atomic update field type

  • AtomicIntegerFieldUpdater
  • AtomicLongFieldUpdater
  • AtomicStampedReference

Two steps:

1. Atomic update field classes are abstract classes. Intelligence uses the static method newUpdater to create a updater and set the classes and properties to be updated

2. Updated class attributes must use public volatile

AtomicIntegerFieldUpdater updater = AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
Copy the code

Concurrent tool

CountDownLatch

When multithreading completes a service function, it sometimes needs to wait for the completion of other threads before the main Thread can continue to perform the service function. In this case, the join method of Thread class can be used to make the main Thread wait for the completion of the joined Thread before the main Thread continues to execute the service function. This can also be done using an inter-thread message communication mechanism.

In fact, Java provides a tool class such as Reiss Countdown to implement this scenario.

The CountDownLatch constructor

public CountDownLatch(int count)
Copy the code

The constructor passes in an integer, and the countDown method calling CountDownLatch subtracts N by 1 until N==0, and the thread currently calling the await method continues.

Methods:

1. Await () : The thread calling the method waits until N passed in by the constructor decreases to 0 before it can proceed

2.await(long timeout, TimeUnit unit)

3. The countDown () :

4.long getCount()

Example:

public class CountDownLatchTest { private static final String TAG = "CountDownLatchTest"; private CountDownLatch refereeSignal = new CountDownLatch(1); Private CountDownLatch playerSignal = new CountDownLatch(6); Private CountDownLatch prepareSignal = new CountDownLatch(6); / / 6 far to mobilize public CountDownLatchTest () {ExecutorService service = Executors. NewFixedThreadPool (6); for (int i = 0; i < 6; i++) { final int index = i; Submit (new Runnable() {@override public void run() {try {log.e (TAG, "" + index + "); prepareSignal.countDown(); refereeSignal.await(); Log.e(TAG, "athlete:" + index + "start sprint "); playerSignal.countDown(); Log.e(TAG, "athlete:" + index + "finish race "); } catch (InterruptedException e) { e.printStackTrace(); }}}); } try { prepareSignal.await(); } catch (InterruptedException e) { e.printStackTrace(); } log. e(TAG, "referee issues gun "); refereeSignal.countDown(); try { playerSignal.await(); } catch (InterruptedException e) { e.printStackTrace(); } log. e(TAG, "all the players in the end focus, competition technique "); service.shutdown(); }}Copy the code

CyclicBarrier

CyclicBarrier is also a multithreaded concurrency control utility that, like CountDownLatch, has wait technology capabilities.

The main method

Public int await() throws InterruptedException, BrokenBarrierException; // public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException; Public Boolean isBroken(); Public int getNumberWaiting(); Public CyclicBarrier(int parties, Runnable barrierAction) public CyclicBarrier(int parties, Runnable barrierAction)Copy the code

Ex. :

public class CyclicBarrierTest { private static final String TAG = "CyclicBarrierTest"; CyclicBarrier cyclicBarrier = new CyclicBarrier(6, new Runnable() { @Override public void run() { Log.e(TAG, "All the athletes are in "); }}); public CyclicBarrierTest() { ExecutorService service = Executors.newFixedThreadPool(6); for (int i = 0; i < 6; i++) { service.submit(new Runnable() { @Override public void run() { Log.e(TAG, Athletes "{" + Thread. CurrentThread (). The getName () +"} enter the "); try { cyclicBarrier.await(); } catch (BrokenBarrierException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } log.e (TAG, "athlete {" + thread.currentThread ().getName() + "} ready to go "); }}); }}}Copy the code

Comparison:

1.CountDownLatch is a thread waiting for multiple threads, and CyclicBarrier is a thread waiting for each other

2. After CountDownLatch is called countDown, the thread will not block; The thread blocks after calling the await method of CyclicBarrier

3. Different number of methods

4. The CyclicBarrier reusable

Semaphore

If you have 5 pens for 10 people, use Acquire to obtain a license to proceed, otherwise you can only block at this method. After release is returned, other threads can continue to execute with a license.

public class SemaphoreTest { private final static String TAG = "SemaphoreTest"; Semaphore mSemaphore = new Semaphore(5); public SemaphoreTest() { ExecutorService service = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { service.execute(new Runnable() { @Override public void run() { Log.e(TAG, Thread.currentthread ().getName() + "Ready to get pen "); try { mSemaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } log.e (TAG, thread.currentThread ().getName()); Log.e(TAG, thread.currentThread ().getName() + "fill in form "); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } mSemaphore.release(); Log.e(TAG, thread.currentThread ().getName() + "put pen back "); }}); }}}Copy the code

Exchanger

If one thread executes the Exchange method first, it synchronizes the other thread to execute the Exchange method. At this point, both threads have reached the synchronization point and the two threads can exchange data

Example: One person walks to the door, waits for the other person to walk to the door synchronization point, and then fights

public class ExchangerTest { private static final String TAG = "ExchangerTest"; Exchanger<String> mExchanger = new Exchanger<>(); public ExchangerTest() { ExecutorService service = Executors.newFixedThreadPool(2); Server.execute (new Runnable() {@override public void run() {try {String king = mExchanger. Exchange (" Let's go to the park and have a fight "); Log.e(TAG, "Long: "+ king); } catch (InterruptedException e) { e.printStackTrace(); }}}); Submit (new Runnable() {@override public void run() {log.e (TAG, "Long walk "); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } try {String loong = mExchanger. Exchange (" I want to punch you too "); Log.e(TAG, "King: "+ loong); } catch (InterruptedException e) { e.printStackTrace(); }}}); }}Copy the code

Producer-consumer

Three ways:

  • 1. Use the wait and notify message notification mechanisms of Object
  • 2. Message notification mechanism using await and signal of Lock Condition
  • 3. Use BlockingQueue