1. What are threads?

Process is the program in the running process, just like wechat and QQ in the mobile phone running, these are called process.

A thread is the execution unit of a process, just like a music software can listen to music, download music, these tasks are done by threads.

  • A process can have multiple threads, and a thread must have a parent process
  • Threads share the shared resources of the parent process and cooperate with each other to complete the tasks required by the process
  • One thread can create and destroy another thread, and multiple threads of the same process can execute concurrently

2. Interrupt the thread

Earlier Versions of Java supported calling the stop method of the thread class directly to interrupt a thread, but this is now enabled, instead

Interrupt () can be used to request the termination of the thread, and the interrupt state of the interrupt() thread will be set each time it is called, so that each thread has a Boolean flag

Thread.currentThread().isInterrupted()
    IsInterrupted () this method true means that a thread has been interrupted
Copy the code

InterruptException is raised when an interrupt() method is called and a thread is blocked by sleep() or wait(). (It also does not detect the thread’s blocking status if it is blocked.)

3. Thread status

3.1 Creating a thread

The steps to create a Thread using the inherited Thread class are as follows:

  1. Create a new class that inherits Thread and overwrites its run() method.
  2. Create an instance of the Thread subclass.
  3. Call the start() method of the subclass instance to start the thread.

Code examples are as follows:

public class ThreadDemo extends Thread {
	
	// 1. Create a class that inherits Thread and override the run() method of Thread.
	@Override
	public void run(a) {
		System.out.println("Hello Thread");
	}
	
	public static void main(String[] args) {
		
		// 2. Create an instance of Thread subclass.
		ThreadDemo threadDemo = new ThreadDemo();
		// 3. Call the start() method of the subclass instance to start the thread.threadDemo.start(); }}Copy the code

The steps to create a thread using the implementation Runnable interface are:

  1. Create a class that implements the Runnable interface and override its run() method.
  2. Create an instance of the implementation class.
  3. Pass this instance into the Thread(Runnable R) constructor to create a Thread instance.
  4. Call the start() method of the Thread object.

Code examples are as follows:

public class RunnableDemo implements Runnable {

	// 1. Create a class that implements the Runnable interface and override its run() method.
	@Override
	public void run(a) {
		System.out.println("Hello Runnable");
	}

	
	public static void main(String[] args) {
		
		// 2. Create an instance of the implementation.
		RunnableDemo runnableDemo = new RunnableDemo();
		
		// 3. Pass this instance into the Thread(Runnable r) constructor to create a Thread instance.
		Thread thread = new Thread(runnableDemo);
		
		// 4. Call the start() method of the Thread object.thread.start(); }}Copy the code

Create thread with Callable and Future:

Runnable encapsulates a task that runs asynchronously. Think of it as an asynchronous method that returns no values or parameters. Callable is similar to Runnale, but has a return value. The parameter type is the type of the return value

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call(a) throws Exception;
}
Copy the code

Future holds the results of asynchronous computations

package java.util.concurrent;

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled(a);

    boolean isDone(a);

    V get(a) throws InterruptedException, ExecutionException;

 
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
Copy the code

3.2 Runnable threads

When the thread calls.start(); Threads are in a runnable state. A runable thread may or may not be running, depending on how long the operating system allows it to run. In fact, a running thread is interrupted to give another thread a chance to run.

Thread scheduling is dependent on the operating system to provide the details of the service, preemptive scheduling system to a runnable thread each time slice to perform the task, when the time slice is used up, deprived of all the threads running operating system, and give another thread to run the opportunity, when choosing the next thread, the operating system consider the priority of a thread.

While all desktop and server operating systems typically use preemptive scheduling, small devices like mobile phones may use collaborative scheduling, where a thread loses control only when yield is invoked or when it is blocked or waiting.

3.3 Blocked and waiting Threads

When a thread is in a blocked or waiting state, it is temporarily inactive, does not run any code and consumes minimal resources until the thread scheduler reactivates it.

When a thread’s lock is held by another thread, the thread will enter the blocking state. The thread will become non-blocking only if the lock is requested and the thread scheduler allows the thread to hold it.

When a thread waits for another thread to notify the scheduler of a condition, it enters the wait state. (Details, p. 5)

3.4 Terminated threads

1. Died of natural causes due to normal launch of the run method.

2. An unexpected death due to an uncaught exception terminating the run method.

4. Thread properties

4.1 Thread Priority

Each thread has a priority, which by default inherits from its parent, or can be set by calling setPriority(1 to 10)

Usually when the thread scheduler has the opportunity to select a new thread, it will preferentially select the thread with a higher priority (the priority of the thread is highly system dependent). For example, Windows has 7 priorities, and some Java priorities are mapped to the host platform’s priorities, with more or less priorities.

4.2 Daemon Thread

t.setDaemon(true); Converting threads to daemon threads

The purpose of a daemon thread is to provide services to other threads. A timing thread is an example of a thread that periodically sends a “timer tick” signal to other threads or empties a stale cache. When there are only daemons left, the virtual machine exits.

4.3 Uncaught exception handlers

The thread’s run method cannot throw any checked exceptions, but not checked exceptions will cause the thread to terminate.

No catch clause is required to handle exceptions that can be propagated, and long before death the exception is passed to a handler for uncaught exceptions

        Install a default handler for each thread
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                
                System.out.println(t+"Default processor"); }});new Thread(new Runnable() {
            @Override
            public void run(a) {
                System.out.println(Thread.currentThread().getId());
                //throw .... ;
            }
        }).start();
Copy the code

A Thread’s run method cannot throw any exceptions that are checked. The exception is passed to uncaughtException(Thread t,Throwable e) in the uncaughtException handler set by the Thread.

If you do not install a default handler for a thread, the default handler will be empty, and if you do not install a default handler for a separate thread, the handler will be the ThreadGroup object for the thread

A thread group is a collection of threads that can be managed uniformly. By default, threads are created to belong to the same thread group, but other groups may be created. Better features have been introduced for handling collections of threads, so it is best not to use thread groups in your own programs

The ThreadGroup class implements thread. UncaughtException, and its UncaughtException method does the following:Copy the code

1. If the thread has a parent thread group, uncaughtException of the parent thread group is called

2. Otherwise, if the Thread getDefaultExceptionHandler method returns a non-null processor, is called the processor

3. Otherwise if Throwable is an instance of ThreadDeath, do nothing

4. Otherwise, the name of the thread and the stack trace of the Throwable are output to system. err.

5. The synchronous

In most practical cases, two or more threads need to share access to the same data if two threads access the same object and each thread modifs the methods of the object’s state. This can lead to serious consequences. According to the order in which each thread accesses data, there may be corrupted objects. This situation is often called race condition.

5.1 An example of competition conditions

5.2 Detailed explanation of competition conditions

5.3 lock object

To protect code from concurrency, Java provided the synchroonized keyword and introduced the ReentrantLock class in Java SE5.0

Synchronized automatically provides a lock and associated conditions.

It is usually necessary to place the unlock in the finally clause after a manual lock, and try statements with resources cannot be used when the lock is used

    private double[] accounts;
    private Lock mlock;
    private Condition sufficientFunds;

    public Bank(int n, int initMenoy) {
        accounts = new double[n];
        for (int i = 0; i < n; i++) {
            accounts[i] = initMenoy;
        }
        mlock = new ReentrantLock();
        sufficientFunds = mlock.newCondition();
    }

	public void transfer(int from, int to, double amont) throws InterruptedException {
        mlock.lock();
        try {
            if (accounts[from] < amont) {
                sufficientFunds.await();
            }
            accounts[from] -= amont;
            accounts[to] += amont;
            sufficientFunds.signalAll();
        } finally {
            mlock.unlock();
            System.out.println("Transfer successful, transfer amount :"+ amont); getAccoutsSum(); }}Copy the code

If a lock is used in a method of an object, when a thread accesses the method of the object, the thread attempts to acquire the lock. If the lock is held by another thread, the thread blocks until another thread executes unlock() on the lock object.

The lock holds a holding counter that tracks nested calls to the lock method

5.4 Conditional Objects

It is common for a thread to call a method and find that the current Condition is not sufficient to perform the following steps. The thread terminates, but there is another way to determine whether the current Condition is satisfied without frequently executing the thread. Simply call the await() method of the Condition in the Condition statement.

The.await() method blocks the thread and waivers the lock, and adds the thread to the condition’s wait set

The thread cannot unblock when the lock is available, but only when another thread’s condition object calls.signalAll() and waits for the dispatcher to re-activate the thread.

    private double[] accounts;
    private Lock mlock;
    private Condition sufficientFunds;

    public Bank(int n, int initMenoy) {... }public void transfer(int from, int to, double amont) throws InterruptedException {
        mlock.lock();
        try {
            if(accounts[from] < amont) { sufficientFunds.await(); }... }finally{ mlock.unlock(); }}Copy the code

.signal() : just randomly pick a thread from the wait set to activate

.signalAll() : Activates all threads in the wait set (not immediately, but simply unblocks the wait threads so that they can compete for access to objects after the current thread exits the synchronous method.)

To reactivate all threads waiting because of the condition, when the thread when removing from the wait for collection, the thread becomes runnable, the scheduler will activate them again, they will try to enter the object’s methods, at the same time when the lock becomes available, some of them will await () call returns, get the lock and from blocked place continue to hold Line.

Deadlock occurs when there are no threads to reactivate the waiting thread

No thread can unblock any other thread and the program hangs.

5.5 the synchronized keyword

The Lock and Condition interfaces provide programmers with a high degree of Lock control that is not required in most cases.

You can use the synchronized keyword. Starting with Java 1.0, every object in Java has an internal lock. If a method is declared with the synchronized keyword, the lock on the object protects the entire method.

    public synchronized void getAccoutsSum(a) {
        double sum = 0;
        for (double b : accounts) {
            sum += b;
        }

// mlock.unlock();
        System.out.println("Current total amount :" + sum);
    }
Copy the code

This code block has the same effect as using Lock above

The.wait() method adds a thread to the wait set

The.notifyall () method dismisses all threads in the wait set

The.nofity() method dissolves a thread in the wait set

5.6 Synchronization Blocking

synchronized(obj) {
	// Synchronize code blocks
}
Copy the code

    public  void getAccoutsSum(a) {  
        synchronized (this) {// Lock the current object
            double sum = 0;
            for (double b : accounts) {
                sum += b;
            }
            System.out.println("Current total amount :"+ sum); }}Copy the code

5.7 Monitor Concepts

5.8 Volatile domain

5.9 final variables

5.10 atomic

Atomicity: In Java, it refers to operations that are indivisible.

When shared variables are not assigned, they can be declared as volatie

5.11 a deadlock

All threads that block are called deadlocks

5.12 Thread-local variables

5.13 Lock Tests and timeouts

    public void transfer(int from, int to, double amont) throws InterruptedException {
        if(mlock.tryLock()){
        mlock.lock();
        try {
            if (accounts[from] < amont) {
                sufficientFunds.await();
            }
            accounts[from] -= amont;
            accounts[to] += amont;
            sufficientFunds.signalAll();
        } finally {
            mlock.unlock();
            System.out.println("Transfer successful, transfer amount :" + amont);
            getAccoutsSum();
        }}else {
            System.out.println("No lock, skip ahead."); }}Copy the code

The lock method attempts to apply for a lock and returns true on success or false otherwise so that the thread can immediately do something else without blocking.

public void transfer(int from, int to, double amont) throws InterruptedException {
    if(mlock.tryLock(100,TimeUnit.MILLISECONDS)){
    mlock.lock();
    try {
        if (accounts[from] < amont) {
            sufficientFunds.await();
        }
        accounts[from] -= amont;
        accounts[to] += amont;
        sufficientFunds.signalAll();
    } finally {
        mlock.unlock();
        System.out.println("Transfer successful, transfer amount :" + amont);
        getAccoutsSum();
    }}else {
        System.out.println("No lock, skip ahead."); }}Copy the code

5.14 Read/Write Lock

If multiple threads often read data and rarely modify it, the following method can save memory.

read Lock(); // Obtain a read lock that can be shared by multiple read operations, but excludes all writes.

write Lock(); // Get a write lock that excludes all other read and write operations

// Construct an object
private ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
// Extract read and write locks
private Lock readLock=rwl.readLock();
private Lock writeLock=rwl.writeLock();
// Lock all fetch methods
public double getBalance(a){
    readLock.lock();
    try{... }finally{readLock.unlock();}
}
// Write lock all modification methods
public voi setBalance(a){
    writeLock.lock();
    try{... }finally{writeLock.unlock();}
}


Copy the code

5.15 Why are the Stop and Supend methods Enabled

Stop: Stop is inherently unsafe because terminating a thread forces it to stop execution, whether the run method is finished or not, and releases all lock objects held by the thread. This phenomenon is seen by other threads that are blocked by requesting the lock, causing them to continue down. This can cause data inconsistencies, we still take bank transfer as an example, we are from A account to account transfer B 500 yuan, we discussed before, the process is divided into three steps, the first step is A minus 500 yuan in the account, if the thread is stop at this time, so this thread will release it to lock, Then the other threads continue to execute, so account A somehow loses $500 and account B doesn’t receive any money. This is the insecurity of the stop method.

Supend :suspend is deprecated because it causes deadlocks. The suspend method, unlike the stop method, does not break an object or force the lock to be released. Instead, it holds the lock until another thread calls the Resume method.

If thread A is blocked by suspend after it has acquired A lock, thread A cannot resume. Thread B can call resume after it has acquired the same lock. However, the lock is occupied by thread A, and thread B cannot resume in time. B Deadlock occurs because neither thread can proceed further. This is why suspend was abandoned.

6. Block the queue

What is a blocking queue? A BlockingQueue is a queue that supports two additional operations. The two additional operations are: when the queue is empty, the thread that fetched the element waits for the queue to become non-empty. When the queue is full, the thread that stores the element waits for the queue to become available. Blocking queues are often used in producer and consumer scenarios, where the producer is the thread that adds elements to the queue and the consumer is the thread that takes elements from the queue. A blocking queue is a container in which producers hold elements, and consumers only take elements from the container.

Blocking queues provide four handling methods:

Method \ Processing method An exception is thrown Return special value Has been blocked Timeout exit
Insert method add(e) offer(e) put(e) offer(e,time,unit)
Remove method remove() poll() take() poll(time,unit)
Check the method element() peek() Do not use Do not use
  • Throw exception: An IllegalStateException(“Queue Full “) will be thrown if an element is inserted into the Queue when the blocking Queue is full. When the queue is empty, NoSuchElementException is thrown when an element is fetched from the queue.

  • Returns a special value: The insert method returns success or true on success. Remove method, which removes an element from the queue or returns NULL if none is present

  • Block: When the blocking queue is full, if the producer thread puts elements to the queue, the queue will block the producer thread until it gets data or exits in response to an interrupt. When the queue is empty, the consumer thread tries to take elements from the queue, and the queue blocks the consumer thread until the queue is available.

  • Timeout exit: When the blocking queue is full, the queue blocks the producer thread for a certain amount of time, and the producer thread exits after a certain amount of time.

    Blocking queues in Java

    JDK7 provides seven blocking queues. , respectively,

    • ArrayBlockingQueue: A bounded blocking queue composed of array structures.
    • LinkedBlockingQueue: A bounded blocking queue consisting of a linked list structure.
    • PriorityBlockingQueue: An unbounded blocking queue that supports priority sorting.
    • DelayQueue: an unbounded blocking queue implemented using a priority queue.
    • SynchronousQueue: A blocking queue that does not store elements.
    • LinkedTransferQueue: An unbounded blocking queue consisting of a linked list structure.
    • LinkedBlockingDeque: A bidirectional blocking queue consisting of a linked list structure.

The code examples

package thread;

import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;

public class BlockingQueneTest {
    public static void main(String[] args) {
        String directpry = "C: \ \ Program Files \ \ Java \ \ JDK - 9.0.4 \ \ bin";
        BlockingQueue<Object> blockingQueue = new ArrayBlockingQueue<>(20);   // The length of the blocking queue
        int pro=5;  // Number of producer threads
        int con=3;	// Number of consumer threads
        for (int i = 0; i < pro; i++) {
            new Thread(new Producer(blockingQueue)).start();
        }
        for (int i = 0; i < con; i++) {
            new Thread(newConsumer(blockingQueue)).start(); }}}class Producer implements Runnable {
    private BlockingQueue<Object> m;

    public Producer(BlockingQueue<Object> m) {
        this.m = m;
    }

    @Override
    public void run(a) {
        try {
            while (true) {
                m.put(get());
                System.out.println("Production time - blocking queue"+m.size()); }}catch (InterruptedException e) {
            System.out.println("Producer interrupt"); }}Object get(a) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("Interruption in production");
        }
        return newObject(); }}class Consumer implements Runnable {
    private BlockingQueue<Object> m;

    public Consumer(BlockingQueue<Object> m) {
        this.m = m;
    }

    @Override
    public void run(a) {
        try {
            while (true) {

                Object o = m.take();
                System.out.println("Fetch - block queue"+m.size()); take(o); }}catch (InterruptedException e) {
            System.out.println("Consumer interruption"); }}void take(Object o) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("Interruption of consumption");
        }
        System.out.println("Consumer object"+ o); }}Copy the code

7. Thread-safe collections

7.1 Efficient mapping tables, sets, and queues

java.util.concurrent Package provides a mapping table, ordered set and queue efficiently, ConcurrentHashMap, ConcurrentSkipListMap, ConcurrentSkipListSet and ConcurrentLinkedQuene

These collections use complex algorithms to minimize contention by allowing concurrent access to different parts of the data structure

7.2 Writing a Copy of an Array

CopyOnWriteArrayList and CopyOnWriteArraySet are thread-safe collections in which all modifying threads copy the underlying array

9. Actuators

Building a new thread is costly because it involves interaction with the operating system. If a large number of short-lived threads are created in a program, then a thread pool should be used. A thread pool contains many idle threads ready to run. When you hand Runnable to the thread pool, one of the threads calls the run method, and when the run method exits, the thread does not die, but is in the pool ready to service the next request.

The Executor class has a number of static factory methods to build thread pools

methods describe
newCachedThreadPool Threads are created if necessary, and idle threads are reserved for 60 seconds
newFixedThreadPool This thread pool contains a fixed number of threads and does not
newSingleThreadExecutor A pool of threads with only one thread that executes each submitted task sequentially
newScheduledThreadPool Single-threaded “pool” built for scheduled execution
newSingleThreadScheduledExecutor Fixed thread pool built for scheduled execution instead of java.util.timer

9.1 the thread pool

public class Pool_demo {

    public static void main(String[] args) {

        Runnable runnable1=new Runnable() {
            @Override
            public void run(a) {
                while (true) {try {
                        Thread.sleep(1000);
                        System.out.println("Current thread ID"+Thread.currentThread().getId()+Thread.currentThread().toString());
                    } catch(InterruptedException e) { e.printStackTrace(); }}}}; ExecutorService executorService1=Executors.newCachedThreadPool();// Create a new thread pool. If there are no free threads available, let them execute the task immediately. If there are no free threads available, create a new thread
        ExecutorService executorService=Executors.newFixedThreadPool(2);  // Create a thread pool of fixed size
        for (int i = 0; i < 3; i++) {
            executorService.submit(runnable1);// Submit the specified task to the thread pool for execution.
        }
        executorService.shutdown();// If the service is shut down, the submitted tasks will be completed first and no new tasks will be accepted
        executorService.shutdownNow();// Close the service, whether the current task is complete or not. And returns a list of tasks that have never been started.
    }

Copy the code

9.2 Scheduled Execution

The ScheduledExecutorService interface has methods designed for scheduled or repeated execution of tasks, and is a generalization of java.util.timer that allows the use of thread pooling mechanisms

ScheduledExecutorService scheduledExecutorService=Executors.newScheduledThreadPool(5);
        Runnable runnable=new Runnable() {
            @Override
            public void run(a) {
                System.out.println("1"); }}; scheduledExecutorService.schedule(runnable,1000,TimeUnit.MILLISECONDS);// Specify a period of time after which to execute the task
        scheduledExecutorService.scheduleAtFixedRate(runnable,1000.1000,TimeUnit.MILLISECONDS);// The given task is scheduled to run periodically after the initial delay expires
        scheduledExecutorService.scheduleWithFixedDelay(runnable,1000.1000,TimeUnit.MILLISECONDS);// The task is scheduled to run periodically after the prompted delay ends, with a delay of length delay between the completion of one call and the start of the next
Copy the code

9.3 Controlling Task Groups

9.4 the Fork – Join framework

The fork-Join framework was introduced in Java SE7 to support applications that use one thread per processor kernel to perform computationally intensive tasks, such as image or video processing. Given a single processing task, it can be naturally decomposed into subtasks

10. Synchronizer

The java.util.Concurrent package contains several classes for thread sets that help people cooperate with each other. These mechanisms have “preset capabilities” for common rendezvous patterns between threads. If there is a cooperative set of threads that meets one of these behavior patterns, then the appropriate library classes should be reused directly rather than trying to provide a manual set of locks and conditions.

synchronizer

class What can it do? When to use
CyclicBarrier Allows a thread set to wait until a predetermined number of threads have reached a common barrier, then optionally perform an action to process the barrier. When a large number of threads need to complete before their results are available
CountDownLatch Allows the thread to wait until the calculator is reduced to 0 When one or more threads need to wait until a specified number of events occur
Exchanger Allows two threads to exchange objects when the object to be exchanged is ready When two threads work on two instances of the same data structure, one adds data to the instance and the other purges data from the instance
Semaphore Allows a thread set to wait until it is allowed to continue running Limit the number of threads that can access a resource, and if the number of permissions is 1, often block threads until another thread gives permission
SynchronousQueue Allows one thread to pass objects to another thread When two threads are ready to pass an object from one thread to the other without showing synchronization

10.1 a semaphore

10.2 Countdown door bolt

10.3 barrier gate

10.4 the switch

10.5 Synchronizing queues

11. Threads and Swing

11.1 Running Time-consuming Tasks

11.2 Using Swing worker threads

11.3 Single thread rule