Processes and threads

process

Process is the process entity running process, is the system for resource allocation and scheduling an independent unit, such as our Windows computer running a program is a process. In the traditional process process is a basic unit of resource allocation and scheduling, with the introduction of the concept of thread, process becomes the basic unit of resource allocation but not the basic unit of scheduling.

Why threads

Before we talk about threads, let’s summarize the characteristics of processes:

  1. A process is an independent unit of available resources;
  2. A process is a basic unit that can be scheduled and dispatched independently.

That may seem fine, but in a multitasking environment, it is not possible to queue all tasks until the first one is finished. If you want the user to feel that the tasks are all executed together, you have to switch frequently between processes. The problem is that it takes a lot of work to switch processes. You have to save the current CPU context for the next time the CPU is assigned to the current process, and then you have to set up the CPU context for the new process, which can take a lot of time. For this reason, the number of processes in the system is limited.

In order to solve this limitation, it was proposed to separate the two attributes of the process and treat them separately by the operating system, that is, as the basic unit of scheduling and dispatching, but not as the unit of owning resources; Base units with resources are not frequently switched. It is under the guidance of this idea that the concept of thread was formed.

thread

In multithreaded operating systems, it is common to include multiple threads in a process, and each thread is a basic unit of independent scheduling and dispatching. Resources are owned by the process, not by the thread. Thread switching between the same process does not cause process switching, only thread switching between different processes can cause process switching. Moreover, thread switching only needs to save and set a small amount of register content, and will not create and destroy process control blocks with process switching requirements, so it is very fast, so it is very suitable for high concurrency environment.

Thread state (Java)

Public enum State {NEW,// A NEW thread is created, but the start method RUNNABLE is not called,// The current thread can run, but the CPU determines whether to run,// other threads are BLOCKED to obtain the lock, // The current thread is in TERMINATED state at lock WAITING,// WAITING for other conditions to be ready to run TIMED_WAITING,// the timing wait is TERMINATED at a specified time and TERMINATED when TERMINATED. // Terminate thread execution completed}Copy the code

How threads are created

Thread

Inheriting Thread class:

class TestThread extends Thread{
        @Override
        public void run() {
            super.run();
            //do working
        }
    }
Copy the code
Runnable

Implement the Runnable interface:

static class TestRunnale implements Runnable{

        @Override
        public void run() {
            //do working
        }
    }

    public static void main(String[] args) {
        TestRunnale runnale = new TestRunnale();
        Thread thread = new Thread(runnale);
        thread.start();
    }
Copy the code

Thread interruption

Unsafe interruption

The Thread API provides several methods for terminating threads, such as stop(), suspend(), and resume(), but these methods are bit-obsolete in the JDK because they are deadlock-friendly and have been explicitly deprecated.

Interrupt thread API

The essence of a thread is to set its interrupt flag bit to true, and other threads say hello to the thread that needs to interrupt. It is up to the thread to decide whether to actually interrupt.

The isInterrupted() thread checks its interrupt flag bit

The static method thread.interrupted () returns the interrupt flag bit to false

Interrupt flag bit

A custom Boolean interrupt flag bit that provides an interrupt method. The thread is constantly checking this flag bit. The flag bit is set to exit to terminate the thread.

Public class FlagCancel {static class Flag extends Thread{public static Boolean Flag =false;

        @Override
        public void run() {
            int i = 0;
            while(! flag){ System.out.println(i++);if(i>=3){
                    try {
                        Thread.sleep(200);
                        //interrupt();
                        if(i == 10) cancel(); System.out.println(system.out.println ("thread:" + isInterrupted());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("cancel...");
                }
            }
        }

        public static void cancel(){
            flag = true;
        }
    }

    public static void main(String[] args) {
        Flag test= new Flag(); test.start(); test.setPriority(10); // The priority set here is useless. The CPU doesn't care about your... try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main:"+ test.isInterrupted()); // This is the main thread}}Copy the code

Normally there is nothing wrong with this. When we write code, we provide a way to change the interrupt to state and define when to interrupt according to our own business logic, but if we set the interrupt manually, we have a problem. To open. The interrupt() method is used to interrupt a thread, but in the above logic it does not interrupt immediately if called and must wait for the interrupt to be modified before exiting.

Safe interrupt

Interrupt apis and the use of interrupt flag bits to interrupt threads were described above, but the interrupt flag bits do not catch exceptions. However, the isInterrupted() method always checks the interrupted status of the thread, so you can use this method to achieve a safe interrupt.

public class SafeInterrupt extends Thread {

    private boolean flag = false;

    @Override
    public void run() {
        int i = 0;
        System.out.println(Thread.currentThread().getName() + ":" +Thread.currentThread().isInterrupted());
        while(! flag && ! Thread.currentThread().isInterrupted()) { System.out.println(i++); try { synchronized (this) {if (i > 3) {
                        //Thread.sleep(1000 * 60 * 60 * 24);
                        wait(a); } } } catch (InterruptedException e) { e.printStackTrace(); @param t(Thread) */ public void cancel(Thread t) {system.out.println (Thread t) {system.out.println ("ready stop currentThread...");
        flag = true; // Set the interrupt flag bit of the thread that needs to interrupt totrue
        t.interrupt();
        System.out.println(t.getName() + ":"+ t.isInterrupted()); } public static void main(String[] args) throws InterruptedException { SafeInterrupt safeInterrupt = new SafeInterrupt(); safeInterrupt.start(); Thread.sleep(100); safeInterrupt.cancel(safeInterrupt); }}Copy the code
Interrupts in ReentrantLock

There is also a lock implementation at the JDK level called ReentrantLock. ReentrantLock has several methods for locking: lock(),tryLock(), and lockInterruptibly(), where lockInterruptibly() is the locking process used in response to an interrupt.

The usage method is not too different from the above example.

An uninterruptible condition

Ok, so now we can safely handle thread interrupts, but we’re not done yet, because not all threads respond to interrupts. For example, read()/write() of IO does not respond to interrupts. To prevent further blocking, we need to manually close the underlying socket.

public class CloseSocket extends Thread {
    private Socket socket;
    private InputStream in;

    public CloseSocket(Socket socket, InputStream in) {
        this.socket = socket;
        this.in = in; } // Override interrupts the socket when the thread interruptsinterrupt() {try {// Close the underlying socket socket.close(); } catch (IOException e) { e.printStackTrace(); }finally {// Interrupt thread super.interrupt(); }}}Copy the code

There are cases of unresponsive interrupts, such as deadlocks, that cannot be solved by code. You can only restart the server by checking for code changes.