The concept of threads

Keywords: Java jvm Windows Linux

Article directory

Introduction to Multithreading

Operating systems (Windows, macOS, Linux) can now perform multiple tasks.

  • Multitask is running multiple tasks at the same time.
  • Operating systems alternate multiple tasks

A task is a process.


In some processes, multiple subtasks can also be performed, such as writing code while using eclipse, spell checking by the compiler, and downloading plug-ins in the background. The subtasks are called threads.

The relationship between processes and threads

  • A process can contain one or more threads (at least one thread)
  • Threads are the smallest unit of task scheduled by the operating system
  • How to schedule threads is entirely up to the operating system

The Method of Realizing Multitask

  • Multiprocess mode (each process has only one thread)
  • Multithread mode (a process has multiple threads)
  • Multiprocess + Multithreading (highest complexity)

Multiprocess VS Multithreading

  • Creating processes is more expensive than creating threads
  • Inter-process communication is slower than inter-thread communication
  • Multiprocess runs more stably than multithreading

Java language has built-in multithreading support

  • A Java program is actually a JVM process
  • JVM uses a main thread to execute the main() method
  • Multiple threads can be started in the main() method

Java's Multithread Characteristics

  • Multithread model is the most basic concurrency model for Java programs
  • Multithread Model since Network, Database, Web, etc.
  • Must master Java multithreaded programming in order to continue in-depth study

Create new threads

Method of Creating Thread Objects

  • Create the MyThread class
    1. Derived from Thread

    2. Override run() method

    3. Create MyThread instances

    4. Call start() to start the thread

       public class Main {
       	public static void main(String[] args) {
       	MyThread mt = new MyThread();
       	mt.start();
       		}
       }
       class MyThread extends Thread{
       	@Override
       	public void run() {
       		System.out.println("Hello World");
       	}
       }
      
  • If a class has been derived from a class, it cannot inherit from Thread:
    1. Implementing Runnable Interface

    2. Override run() method

    3. Create a Runnable instance in the main() method

    4. Create a Thread instance and pass in an instance of Runnable

    5. Call start() to start the thread

       public class Main {
       
       	public static void main(String[] args) {
       		Runnable r = new MyThread();
       		Thread t = new Thread(r);
       		t.start();
       	}
       
       }
       
       class MyThread implements Runnable{
       
       	@Override
       	public void run() {
       		// TODO Auto-generated method stub
       		System.out.println("Hello World");
       	}
       	
       }
      

The direct call to run() method is invalid, and the direct call to run() method is equivalent to calling a normal function, which does not start a new thread.
The definition of start() in the Thread class, where the call to start(0) is implemented by C code inside the JVM.

class Thread implements Runnable {
	/**
	     * Causes this thread to begin execution; the Java Virtual Machine
	     * calls the <code>run</code> method of this thread.
	     * <p>
	     * The result is that two threads are running concurrently: the
	     * current thread (which returns from the call to the
	     * <code>start</code> method) and the other thread (which executes its
	     * <code>run</code> method).
	     * <p>
	     * It is never legal to start a thread more than once.
	     * In particular, a thread may not be restarted once it has completed
	     * execution.
	     *
	     * @exception  IllegalThreadStateException  if the thread was already
	     *               started.
	     * @see        #run()
	     * @see        #stop()
	     */
	    public synchronized void start() {
	        /**
	         * This method is not invoked for the main method thread or "system"
	         * group threads created/set up by the VM. Any new functionality added
	         * to this method in the future may have to also be added to the VM.
	         *
	         * A zero status value corresponds to state "NEW".
	         */
	        if (threadStatus != 0)
	            throw new IllegalThreadStateException();
	
	        /* Notify the group that this thread is about to be started
	         * so that it can be added to the group's list of threads
	         * and the group's unstarted count can be decremented. */
	        group.add(this);
	
	        boolean started = false;
	        try {
	            start0();
	            started = true;
	        } finally {
	            try {
	                if (!started) {
	                    group.threadStartFailed(this);
	                }
	            } catch (Throwable ignore) {
	                /* do nothing. If start0 threw a Throwable then
	                  it will be passed up the call stack */
	            }
	        }
	    }
	    private native void start0();
}

thread priority

  • Threads can be prioritized

      	Thread.setPriority(int n)	//1-10, default value 5
    
  • Threads with high priority have high priority in operating system scheduling

  • You can't ensure the execution order of functions by setting priorities

  • No priority setting is recommended for threads

Status of threads

  • A thread object can only call a run() method once
  • The thread's execution code is the run() method
  • Thread scheduling is determined by the operating system, but not by the program itself.

Status of threads

  • New (New)
  • Runnable (in operation)
  • Blocked
  • Waiting (Waiting)
  • Timed Waiting
  • Terminated (terminated)

Reasons for thread termination:

  • run() method executes to return statement return (thread terminates normally)
  • Thread termination due to uncovered exceptions (thread unexpected termination)
  • Call the stop() method on a Thread instance of a thread (not recommended)

One thread can wait for another thread to know its end. As follows, when the main thread calls t.join, the main thread will wait for the thread represented by variable t to end.

public class Main {
	public static void main(String[] args) {
		Runnable r = new MyThread();
		Thread t = new Thread(r);
		System.out.println("START");
		t.start();
		try {
			t.join();
		} catch (InterruptedException e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
		}
		System.out.println("END");
	}

}

class MyThread implements Runnable{
	@Override
	public void run() {
		System.out.println("Hello World");
	}
}

Interrupt thread

  • If a thread needs to perform a long task, it may need to interrupt the thread

  • An interrupt thread is a thread that is given a limit by other threads. The thread receives a signal and ends executing the run() method.

  • Interrupt threads need to detect isInterrupted() flags

  • Other threads terminate the thread by calling interrupted() method

      public class Main {
      	public static void main(String[] args) throws InterruptedException {
      		Thread t = new HelloThread();
      		t.start();
      		Thread.sleep(1000);
      		t.interrupt();
      	}
      }
      
      class HelloThread extends Thread{
      	@Override
      	public void run() {
      		while(!isInterrupted()){
      			System.out.println("Hello World");
      		}
      	}
      	
      }
    

If the thread is in a waiting state, it will capture InterruptedException

  • Capturing InterruptedException indicates that other threads have invoked the interrupted() method, which should normally terminate immediately.

      class HelloThread extends Thread{
      	@Override
      	public void run() {
      		while(!isInterrupted()){
      			System.out.println("Hello World");
      			try {
      				Thread.sleep(100);
      			} catch (InterruptedException e) {
      				e.printStackTrace();
      				return;
      			}
      		}
      	}
      }
    
  • You can set the running flag bit

  • Sharing variables between threads requires volatile keyword tags to ensure that threads can read updated variable values.

    Interpretation: In the Java Virtual Machine, the value of a variable is stored in main memory, but when a thread accesses a variable, it first gets a copy and saves it in its own working memory. If the thread modifies the value of the variable, the virtual opportunity writes the modified variable back to main memory at a certain time, but the time is uncertain. This leads to the fact that if a thread updates a variable, the value read by another thread may still be prior to updating, such as the variable a = true in main memory, and a = false in thread execution. At this point, only a copy of a in thread one becomes false, while a = true in main memory. If Thread 2 reads the value of a at this time, it reads a = true.

In the following example, the volatile keyword is intended to tell the virtual machine:

  • Every time a variable is accessed, it always gets the latest value of main memory

  • Write back to main memory every time a variable is modified

      public class Main {
      	public static void main(String[] args) throws InterruptedException {
      		HelloThread t = new HelloThread();
      		System.out.println("START");
      		t.start();
      		Thread.sleep(1000);
      		t.running = false;
      		System.out.println("END");
      	}
      }
      
      class HelloThread extends Thread{
      	
      	public volatile boolean running = true;
      	
      	@Override
      	public void run() {
      		while(running){
      			System.out.println("Hello World");
      		}
      	}
      	
      }
    

The volatile keyword solves the visibility problem:

  • When a thread modifies the value of a shared variable, other threads can immediately see the modified value.

Daemon thread

The entry to a Java program is when the JVM starts the main thread

  • The main thread can start other threads
  • When all threads end running, the JVM exits and the process ends.

There is a thread whose purpose is to loop indefinitely.

  • Timing task

If a thread does not end, the JVM process cannot end.

  • Who is responsible for terminating such threads?

Daemon

  • Daemon threads are threads that serve other threads
  • When all non-daemon threads are executed, the virtual machine exits

Characteristics of daemon threads

  • Daemon threads cannot hold resources (such as opening files)
    Because when the virtual machine exits, the daemon thread has no chance to close the file, which will result in data loss.

Create daemon threads

class TimerThread extends Thread {
	@Override
	public void run() {
		while (true) {
			System.out.println(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				break;
			}
		}
	}
}

public class Main {

	public static void main(String[] args) throws Exception {
		System.out.println("Main start");
		TimerThread t = new TimerThread();
		t.setDaemon(true);//Set this thread as a daemon thread
		t.start();
		Thread.sleep(5000);
		System.out.println("Main end");
	}
}

Posted by simrx11 on Thu, 19 Sep 2019 03:26:14 -0700