Thread World in JAVA

Processes and Threads

  • Processes are the basic unit by which a program requests resources from the operating system, such as memory space and file handles.
  • Threads are the smallest unit of independently executable execution in a process.

JAVA Thread API

  1. Creating a thread in Java creates an instance of the Thread class.
  2. Each thread has its own task to perform. Thread task processing logic is implemented or invoked in the run method of the Thread class, so the run method is equivalent to the entry method for thread task logic processing, which is invoked by the java virtual machine when the corresponding thread is running, not by the application code.
  3. The start method of the Thread class is used to start related threads. The essence of starting a thread is to ask the java virtual machine to run the corresponding thread, and when the thread runs is determined by the thread scheduler. Therefore, although the start method is executed, this does not mean that the thread starts running. It may or may not run later.
  4. Two constructors commonly used in Thread are Thread() and Thread(Runnable target), which create threads in the following ways:

    1. Create threads by defining subclasses of the Thread class

      public class WelcomeApp {
      
        public static void main(String[] args) {
          // Create Threads
          Thread welcomeThread = new WelcomeThread();
      
          // Start Thread
          welcomeThread.start();
      
          // Output Thread Name for Current Thread
          System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName());
        }
      }
      
      // Define subclasses of the Thread class
      class WelcomeThread extends Thread {
      
        // Implementing task processing logic for threads in this method
        @Override
        public void run() {
          System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName());
        }
      }
      
    2. Create threads by implementing the Runnable interface

      public class WelcomeApp1 {
      
        public static void main(String[] args) {
          // Create Threads
          Thread welcomeThread = new Thread(new WelcomeTask());
      
          // Start Thread
          welcomeThread.start();
          // Output Thread Name for Current Thread
          System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName());
      
        }
      
      }
      
      class WelcomeTask implements Runnable {
        // Implementing task processing logic for threads in this method
        @Override
        public void run() {
          // Output Thread Name for Current Thread
          System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName());
        }
      
      }
  5. Regardless of how you run it, once the thread's run method finishes executing, the corresponding thread finishes running, and the resources occupied by the running thread are garbage collected by the java virtual machine just like other java objects.
  6. An instance of Thread can only start once, and multiple calls to start() of an instance throw an IllegalThreadStateException exception.
  7. You can use Thread.currentThread() gets the current thread, which in turn can set its properties or get information about it, such as:

    Thread.currentThread().setName("thread A");
    Thread.currentThread().getName();
  8. In the above, the run method of a thread is usually called by a java virtual machine. However, a thread is also an instance of a Thread class, and the run method is also decorated by the public modifier. Therefore, the run method can also be called directly, but it is not usually done, which violates the original intention of our bedframe threads.

    public class WelcomeApp {
    
      public static void main(String[] args) {
        // Create Threads
        Thread welcomeThread = new WelcomeThread();
        // Start Thread
        welcomeThread.start();
        // Output Thread Name for Current Thread
        System.out.printf("1.Welcome! I'm %s.%n", Thread.currentThread().getName());
        welcomeThread.run();
      }
    }
    
    // Define subclasses of the Thread class
    class WelcomeThread extends Thread {
    
      // Implementing task processing logic for threads in this method
      @Override
      public void run() {
        System.out.printf("2.Welcome! I'm %s.%n", Thread.currentThread().getName());
      }
    }
    ==================Result==================
    1.Welcome! I'm main.
    2.Welcome! I'm Thread-0.
    2.Welcome! I'm main.
    
  9. Thread Properties

    attributeAttribute type and purposeread-onlyImportant considerations
    number
    ID
    Used to identify different threads with different numbersyesWhen a numbered thread has finished running, it may be used by subsequently created threads. Different threads have different numbers, but the uniqueness of the numbers is only valid for one run of the Java virtual machine. That is, after restarting a Java virtual machine, such as a Web server, some threads may be numbered the same as a thread that was last run by the Java virtual machine, so the value of this property is not appropriate for a unique identity, especially as a unique identity in the database, such as a primary key.
    Name
    Name
    Used to distinguish between different threads. The default value is related to the number of the thread in the format Thread-Thread-Thread Number, such as Thread-0noJava does not prevent us from setting the name property of different threads to the same value. Nevertheless, setting the thread's name property can help with code debugging and problem location
    Thread Category
    Daemon
    A value of true indicates that the corresponding thread is a daemon thread, otherwise the corresponding thread is a user thread. The default value of this property is the same as that of the parent thread of the corresponding thread. When a java program is stopped normally, the virtual machine will not stop immediately when a user thread has not finished executing and will wait for its execution to complete. However, if only the daemon thread has not finished executing, it will not prevent the virtual machine from stopping, which indicates that daemon threads are often used to perform tasks of lesser importance. For example, monitoring other threadsnoThis property must be set before the corresponding thread starts, that is, the call to the setDaemon method must precede the call to the start method, or the setDaemon method will throw an IllegalThreadStateException exception. Threads responsible for some critical task processing are not suitable to be set as Daemons
    priority
    Priority
    This property is essentially a hint to the thread scheduler to indicate which thread the application wants to run first. Java defines 10 priorities ranging from 1 to 10. The default value is generally 5. For a specific thread, the default priority value is equal to the priority value of its parent thread, the thread that created itnoThe default priority is usually sufficient. Setting this property value inappropriately can cause serious problems (thread hunger)
  10. Thread method

    MethodfunctionRemarks
    static Thread
    currentThread()
    Returns the current thread, the execution thread (object) of the current codeSame code pair Thread. A call to currentThread(), whose return value may correspond to a different thread (object)
    void run()Task processing logic for implementing threadsThis method is called directly by a Java virtual machine and should not normally be called by an application
    void start()Start corresponding threadThe return of this method does not mean that the corresponding thread has been started. The start method of a Thread instance can only be called once, and multiple calls can cause an exception to be thrown
    void join()Wait for the corresponding thread to finish runningIf Thread A calls the join method of Thread B, the execution of Thread A is suspended until the end of Thread B
    static void yield()Causes the current thread to voluntarily abandon its occupation of the processor, which may cause the current thread to be pausedThis method is unreliable. The current thread may continue to run when the method is called (depending on the current state of the system)
    static void sleep(long millis)Sleep (pause) the current thread for the specified time

Relationship between Thread and Runnable

  1. Thread class implements Runnable interface

    public class Thread implements Runnable{}
    
    
  2. Runnable is an interface and has only one method, so the class implementing Runnable has to re run the method.
  3. The process of executing task logic in two ways

    • Implement the Runnable interface, override the run method

      class WelcomeTask implements Runnable {
        @Override
        public void run() {
          //Task logic 
        }
      }
      
      new Thread(new WelcomeTask()).start();

      The WelcomeTask instance is passed in Thread, which is eventually assigned to a target member variable in Thread

      private Runnable target;

      The specific process is as follows:
      1. A parametric constructor that generates a ThreadName, for example, Thread-0

      public Thread(Runnable target) {
          init(null, target, "Thread-" + nextThreadNum(), 0);
      }

      2. Enter the first initialization function, there is no need to focus on other parameters, as there are other constructors that call init(...)

      private void init(ThreadGroup g, Runnable target, String name,long stackSize){
          init(g, target, name, stackSize, null, true);
      }

      3. Layer 2 initialization function, i.e. target assignment

      private void init(ThreadGroup g, Runnable target, String name,
                        long stackSize, AccessControlContext acc,
                        boolean inheritThreadLocals) {
          if (name == null) {
              throw new NullPointerException("name cannot be null");
          }
      
          this.name = name;
          .....
          this.target = target;
          ....
      }

      4. The Thread instance calls the start() method

      public synchronized void start() {
          //ThreadStatus!= 0 means this Thread instance has already been started (), so it throws an exception
          if (threadStatus != 0)
              throw new IllegalThreadStateException();
          ...
          try {
              //The local method start0() will eventually be called to start this thread
              start0();
              ...
          } finally {
              ...
          }
      }

      5. Local method starts the thread, handing it over to the virtual machine's thread scheduler

      private native void start0();

      6. Thread Scheduler Executes Thread Task Logic

      //When a thread is started, the dispatcher helps us run the execution thread run() method, which is the task logic
      //If target!= When null calls the task logic implemented in WelcomeTask, otherwise nothing will be executed
      public void run() {
          if (target != null) {
              target.run();
          }
      }
      
    • Inherit Thread class, override run method

      class WelcomeThread extends Thread {
           @Override
           public void run() {
             //Task logic
           }
      }
          
      new WelcomeThread().start();
      ...
      //Task Scheduler directly calls the task logic implemented in WelcomeThread
  4. The difference between the two ways

    • Object-oriented angle: One is to implement extends Thread based on inheritance, the other is to combine new Thread(new Runable()) which is less coupled to inheritance.
    • Angle of object sharing: A CountingTask instance can be shared by multiple threads, so there may be competition for resources.

      class CountingThread extends Thread {
          int count = 0;
          @Override
          public void run() {
              for (int i = 0; i < 100; i++) {
                  i++;
              }
          }
          System.out.println("count:" + count);
      }
      
      class CountingTask implments Runnable {
          int count = 0;
          @Override
          public void run() {
              for (int i = 0; i < 100; i++) {
                  i++;
              }
          }
          System.out.println("count:" + count);
      }
      
      public static void main(String[] args) {
          Thread thread;
          CountingTask task = new CountingTask();
          for(int i = 0;i < 10;i++){
              thread = new Thread(task);
              thread.start();
          }
          for(int i = 0;i < 10;i++){
              thread = new CountingThread();
              thread.start();
          }
      }

Thread life cycle

  1. New (New Creation)
    Thread thread = new Thread();
    At this point the thread is just ready for new and does not start execution.
  2. Runnable
    thread.start();
    1.ready: No resources have been allocated yet.
    2.running: Executing.
  3. block
    1.Blocked does not acquire a lock for synchronized protected code.
    2.Waiting

     1.Object.wait(); 
         - o.notify()/o.notifyAll()
     2.Thread.join(); 
         - join Thread End/Interrupted 
     Blocked and Waiting The difference is Blocked Waiting to release a resource, Waiting Is waiting for a condition to be reached.
  4. Time Waiting sets some blockages for the time parameter.
    1.Thread.sleep(m);

      - Time-out/join End of process/Interrupted.

    2.Object.wait(m)

     - Time out/o.notify()/o.notifyAll() 

    3.Thread.join(m)

     - Time-out/join End of process/Interrupted.
  5. Terminated (Terminated)
    1. The run method has finished executing normally.
    2. An exception that was not caught occurred and terminated unexpectedly.

Keywords: Java Back-end Multithreading Concurrent Programming

Added by dt192 on Sat, 05 Mar 2022 19:05:41 +0200