Multi-threaded programming (1)

Article directory

  • multithreaded programming
    • 1. Create multithreading
    • 2. Thread class and common methods
      • 2.1 Common construction methods of Thread
      • 2.2 Common properties of Thread
      • 2.3 Start a thread – start()
      • 2.4 Dormant current thread – sleep()
      • 2.5 Waiting for a thread – join()
      • 2.6 Get current thread reference
      • 2.7 Interrupting a thread
    • Three, the state of the thread

Multithreaded programming

1. Create multi-thread

Method 1: Inherit the Thread class

public class ThreadDemo1 {<!-- -->
    public static void main(String[] args) {<!-- -->
        MyThread t = new MyThread();
        t.start();//Start a new thread and execute run() in the t thread at the same time, and the threads do not affect each other
    }

}

class MyThread extends Thread{<!-- -->
    @Override
    public void run() {<!-- -->
        System.out.println("Thread starts executing");
    }
}
  • Anonymous inner class creates Thread subclass object

    Thread t = new Thread(){<!-- -->
                @Override
                public void run() {<!-- -->
                    System.out.println("Thread starts executing");
                }
      };
    

Method 2: Implement the Runnable interface

public class ThreadDemo3 {<!-- -->
    public static void main(String[] args) {<!-- -->
        Thread t = new Thread(new MyThread3());
        t. start();
    }
}
class MyThread implements Runnable{<!-- -->
    @Override
    public void run() {<!-- -->
       System.out.println("MyThread thread");
    }
}
  • Anonymous inner class creates Runnable subclass object

     Thread t = new Thread(new Runnable() {<!-- -->
                  @Override
                    public void run() {<!-- -->
                       System.out.println("MyThread thread");
                    }
            });
    
  • lambda expression creates Runnable subclass object

Thread t = new Thread(() -> {<!-- -->
    System.out.println("Thread thread");
}
});

2. Thread class and common methods

2.1 Common construction methods of Thread

Method Description
Thread() Create thread object
Thread(Runnable target) Use the Runnable object to create a thread object
Thread(String name) Create a thread object and name
Thread(Runnable target, String name) Use Runnable The object creates a thread object and names it

Thread t1 = new Thread();

Thread t2 = new Thread(new MyRunnable());

Thread t3 = new Thread(“thread name”);

Thread t4 = new Thread(new MyRunnable(), “thread name”);

A thread how can we see his name? What is the use of setting the name?

public class ThreadDemo {<!-- -->
    public static void main(String[] args) {<!-- -->
        Thread t = new Thread(()->{<!-- -->
            while(true){<!-- -->
                System.out.println("Thread thread");
                try {<!-- -->
                    Thread. sleep(1000);
                } catch (InterruptedException e) {<!-- -->
                    e.printStackTrace();
                }
            }
        });
        t. start();
        while(true){<!-- -->
            System.out.println("main thread");
            try {<!-- -->
                Thread. sleep(3000);
            } catch (InterruptedException e) {<!-- -->
                e.printStackTrace();
            }
        }
    }
}
  1. Run the ThreadDemo program
  2. Find the jconsole.exe file in our local JDK path, double-click to open it

C:\Program Files\Java\jdk1.8.0_291\bin\jconsole.exe

  1. Here we can see the program running locally, select and click the link

image-20230317105544516

  1. Select Thread, below we can observe all the running threads in ThreadDemo. Among them, Thread-0 is the thread created by ourselves, which is when the thread name is not set.

    image-20230317105902051

Modify the code:

Thread t = new Thread(()->{<!-- -->
    while(true){<!-- -->
        System.out.println("Thread thread");
        try {<!-- -->
            Thread. sleep(1000);
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }
    }
},"My thread");

image-20230317110118871

Function: Using jconsole is convenient for us to observe the running status of the thread, and setting the thread name is helpful for us to distinguish the thread.

2.2 Common properties of Thread

Attribute Method Description
ID getId() ID is The unique identifier of the thread, different threads will not repeat
name getName() The name is used by various debugging tools
State getState() The status indicates the current situation of the thread
Priority getPriority() Threads with high priority are theoretically easier to be scheduled to
Whether the background thread isDaemon() JVM will stop running after all non-background threads of a process end
Whether it is alive isAlive() Whether the run method is running It’s over
Is it interrupted isInterrupted() Whether to stop running
  1. The Thread constructor can set the thread name, or we can only set the thread name with setName().
  2. Thread priority has the following characteristics:
  • The priority of Java threads ranges from 1 to 10;
  • The default priority of Java threads is 5;
  • The priority of a Java thread is inherited from the thread that created it.
  1. Difference between foreground thread and background thread
    • isDaemon() is true: the background thread will not prevent the end of the java process, even if the background thread has not finished executing.
    • False: The foreground thread will prevent the end of the java process. Only after all the foreground processes are executed, the java process can end.

2.3 Start a thread -start()

public class ThreadDemo {<!-- -->
    public static void main(String[] args) {<!-- -->
        Thread t = new Thread(()->{<!-- -->
            while(true){<!-- -->
                System.out.println("Thread thread");
            }
        });
        t. start();
        while(true){<!-- -->
            System.out.println("main thread");
        }
    }
}

t.start() : Whether it is a thread created by inheriting Thread or implementing the Runnable interface, it can only be regarded as creating a thread, and does not actually start execution, only when calling start method, a thread is actually created at the bottom of the operating system.

Threads are independent streams of execution

The t thread and the main thread are executed independently and do not affect each other, which is why the console will alternately output content.

image-20230317113147362

The difference between t.start() and t.run(): t.run() can also execute threads, but it is executed on the basis of the current thread. Continue to execute the current thread, which affects the execution of other threads, so that the program cannot be executed concurrently.

Observe the code and analyze the results

public static void main(String[] args) {<!-- -->
    Thread t = new Thread(new Runnable() {<!-- -->
        @Override
        public void run() {<!-- -->
            System.out.println("1");
        }
    });
    t. start();
    System.out.println("2");
}

From the console output, we can see that most of 2 will be output before 1, but the case that 1 is output before 2 cannot be ruled out.

Reason: thread creation also has overhead

2.4 Dormant current thread – sleep()

**Function:**It can suspend the current thread for a period of time, and then run normally again.

**Unit:** milliseconds

Because thread scheduling is uncontrollable, this method can only guarantee that the actual sleep time is greater than or equal to the sleep time set by the parameter.

public class ThreadDemo {<!-- -->
    public static void main(String[] args) {<!-- -->
        Thread t = new Thread(()->{<!-- -->
            while(true){<!-- -->
                System.out.println("Thread thread");//Output the result every second
                try {<!-- -->
                    Thread. sleep(1000);
                } catch (InterruptedException e) {<!-- -->
                    e.printStackTrace();
                }
            }
        });
        t. start();
    }
}

2.5 Waiting for a thread-join()

Since the execution of threads is random, sometimes we need to wait for a thread to complete its work before proceeding to the next step. For example, Zhang San only decides whether to save money after waiting for Li Si to transfer money successfully. At this time, we need a method to explicitly wait for the end of the thread.

public class ThreadDemo7 {<!-- -->
    public static void main(String[] args) throws InterruptedException {<!-- -->
        Thread t = new Thread(()->{<!-- -->
                for (int i = 0; i < 5; i ++ ) {<!-- -->
                    System.out.println("t thread");
                    try {<!-- -->
                        Thread. sleep(1000);
                    } catch (InterruptedException e) {<!-- -->
                        e.printStackTrace();
                    }
                }
        });
        t. start();
        //1. No parameters: keep waiting
        //2. There are parameters: when it reaches a certain time, it will not wait, and the two threads will execute at the same time
        t. join();
     // t.join(3000);//main thread waits for t thread for 3 seconds
        System.out.println("main thread");
    }
}

image-20230317114517230

  1. no parameters

After using t.join, the main thread can only execute after the execution of the t thread ends.

If the t thread does not end all the time, then main becomes a blocked waiting state, waiting for the t thread to finish executing.

  1. has parameters

If the waiting time is set, it will not continue to wait.

image-20230317114912118

2.6 Get current thread reference

Returns the object of the current thread

public class ThreadDemo {<!-- -->

   public static void main(String[] args) {<!-- -->

     Thread thread = Thread. currentThread();

     System.out.println(thread.getName());

  }

}

2.7 Interrupting a thread

Method 1: Use a variable to control the execution of threads

public static boolean flag = false;

 public static void main(String[] args) {<!-- -->
  //The flag at this time is a local variable, and the lambda expression must satisfy the variable capture (the variable is modified by final or is actually final, that is, it will not be modified)
 // boolean flag = false;
     Thread t = new Thread(()->{<!-- -->
         while(!flag){<!-- -->
             System.out.println("Thread thread");
             try {<!-- -->
                 Thread. sleep(1000);
             } catch (InterruptedException e) {<!-- -->
                 e.printStackTrace();
             }
         }
         System.out.println("Thread thread terminated");
     });
     t. start();

     try {<!-- -->
         Thread.sleep(3000);//The main thread sleeps for 3 seconds, that is, let the branch thread execute for 3 seconds, and then stop
     } catch (InterruptedException e) {<!-- -->
         e.printStackTrace();
     }
    flag=true;
 }

Method 2: Use Thread built-in flags

public static void main(String[] args) {<!-- -->
    Thread t = new Thread(()->{<!-- -->

        //Thread.currentThread() gets the current thread t
        //isInterrupted built-in identifier, the default is false
        while(!Thread.currentThread().isInterrupted()){<!-- -->
            System.out.println("Thread thread");
            try {<!-- -->
                //After being awakened from sleep, report an exception and check interrupt, and change true to false
                Thread. sleep(1000);
            } catch (InterruptedException e) {<!-- -->
                e.printStackTrace();
                //The thread will not stop after an exception is reported, and the break will end.
                //break;
            }
        }
    });

    t. start();

    try {<!-- -->
        Thread. sleep(3000);
    } catch (InterruptedException e) {<!-- -->
        e.printStackTrace();
    }
    //Set to true to indicate interruption
    //Wake up the sleep() of the t thread, and then set it to false
    //Multiple t.interrupt(); only one exception will be reported
    t. interrupt();
}

The function of the interrupt method:

  1. Set the flag bit to true
  2. If the thread is in a blocked state (executing sleep()), it will wake up the blocked state and end the sleep by running an exception.

The above code will not stop running after an exception is reported:

When sleep is woken up, it will automatically clear the flag (true => false)

so that the next cycle can be executed normally

Solution: Execute break while reporting exception

3. Thread status

NEW: Work has been arranged, no action yet

RUNNABLE: Workable. It can be divided into working and about to start working.

BLOCKED: These all mean waiting in line for other things

WAITING: These all mean waiting in line for other things

TIMED_WAITING: These all mean waiting in line for other things

TERMINATED: Job done

thread status