Summarize the basic usage of Thred, including thread creation, thread interruption, thread waiting, thread sleep, and thread instance acquisition

1. Several common ways of writing threads

1. Create a class that inherits Thread and rewrites run (this way of writing, thread and task content are bound together)

class MyThread extends Thread{
    
    
    @Override
    public  void run(){
    
    
        while(true){
    
    
            System.out.println("hello Thread");
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}
public class Demo1 {
    
    
    public static void main(String[] args) {
    
    
        // 创建一个线程
        // Java 中创建线程, 离不开一个关键的类, Thread
        // 一种比较朴素的创建线程的方式, 是写一个子类, 继承 Thread, 重写其中的 run 方法.
        Thread t=new MyThread();
        t.start();
        while(true){
    
    
            System.out.println("hello main");
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }

    }
}

2. Create a class, implement the Runnable interface, and rewrite run.

The Runnable created here is equivalent to defining a task (what to do with the code), or need a Thread instance to hand over the task to Thread, or call start to create a specific thread

This way of writing, threads and tasks are separated (better decoupling)

Between modules/codes, the closer the relationship is, the higher the coupling is, and the less close the relationship is, the lower the coupling is (writing code is to pursue low coupling and high cohesion)

class MyRunnable implements Runnable{
    
    

    @Override
    public void run() {
    
    
        while(true){
    
    
            System.out.println("hello thread");
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}
public class Demo2 {
    
    
    public static void main(String[] args) {
    
    
        MyRunnable runnable=new MyRunnable();
        Thread t=new Thread(runnable);
        t.start();
        while(true){
    
    
            System.out.println("hello main");
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-1VidjJeR-1661760136664)(.../md file picture backup/image-20220729155530456.png)]

Q: Why do Thread, Runnable, and InterruptedException not require import? (What kind of class can be used directly without import)

Answer: Either the class is in the same package, or the class is in java.lang (lang is imported by default)

3. Still use the inherited Thread class, but no longer explicit inheritance, but use "anonymous inner class"

The Thread instance is the representation of a thread in Java. In fact, to run it, you still need a thread in the operating system.

public class Demo3 {
    
    
    public static void main(String[] args) {
    
    
        Thread t=new Thread(){
    
    
            @Override
            public void run() {
    
    
                while(true){
    
    
                    System.out.println("hello thread");
                    try {
    
    
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
            }
        };
        t.start();
    }
}

4. Use Runnable, which is used as an anonymous inner class

public class Demo4 {
    
    
    public static void main(String[] args) {
    
    
        Thread t=new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                while(true){
    
    
                    System.out.println("hello thread");
                    try {
    
    
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
            }
        });
        t.start();
    }
}

5. Use lambda expressions to define tasks (recommended practice)

public class Demo5 {
    
    
    public static void main(String[] args) {
    
    
        Thread t=new Thread(()->{
    
    
            while(true){
    
    
                System.out.println("hello thread");
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        });
        t.start();
    }
}

A lambda expression is essentially just an anonymous function (a function that has no name and is used only once)

In fact, there are other ways to create threads, based on Callable/FutureTask, based on thread pool...

A classic interview question: What are the ways to create threads in Java?

Answer: at least 7

2. Thread interruption

isInterrupted()

Start a thread start()

  • Creating a Thread instance does not actually create a thread in the operating system kernel
  • Calling start is the real creation of threads in the system and the real execution of tasks

The execution of the thread ends: as long as the entry method of the thread is executed, the thread will end (the entry method of the main thread can be regarded as the main method)

Correspondingly, the so-called "interrupt thread" is to let the thread finish executing the entry method as soon as possible

Method 1 : Use your own flag directly to distinguish whether the thread is about to end

public class Demo9 {
    
    
    // 用一个布尔变量表示线程是否要结束.
    // 这个变量是一个成员变量, 而不是局部变量
    private static boolean isQuit = false;
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread t=new Thread(()->{
    
    
            System.out.println("新线程运行中");
            while(!isQuit){
    
    
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
            System.out.println("新线程执行结束");
        });
        t.start();
        Thread.sleep(5000);
        System.out.println("控制线程退出");
        isQuit=true;
    }
}

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-fsvExMrh-1661760263272)(.../md file picture backup/image-20220730222130022.png)]

Method 2 : Use the flag that comes with Thread

public class Demo10 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread t=new Thread(()->{
    
    
            while(!Thread.currentThread().isInterrupted()){
    
    
                System.out.println("线程运行中");
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
//                    e.printStackTrace();
                    // [1] 立即退出
                    break;

                   // System.out.println("新线程即将退出!");
                    // [2] 稍后退出, 此处的 sleep 可以换成任意的用来收尾工作的代码
//                    try {
    
    
//                        Thread.sleep(3000);
//                    } catch (InterruptedException ex) {
    
    
//                        ex.printStackTrace();
//                    }
//                    break;

                    // [3] 不退出! 啥都不做, 就相当于忽略了异常.
                }
            }
            System.out.println("新线程已经退出");
        });
        t.start();
        Thread.sleep(5000);
        System.out.println("控制新线程退出!");
        t.interrupt();
    }
}

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-4ynhJa1r-1661760263273)(.../md file picture backup/image-20220730223921322.png)]

Pay attention to understand the behavior of the interrupt method:

  • If the t thread is not in a blocked state, interrupt will modify the built-in flag at this time
  • If the t thread is in the blocked state again, interrupt will cause the internal blocking method of the thread at this time, for example, sleep throws an exception InterruptedException

Here is an explanation of the meaning of these two sentences,

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-eBaKRZ14-1661760263274)(.../md file picture backup/image-20220731183518086.png)]

Because there is a sleep method in the thread here, the blocking method is generated inside the thread, that is, the sleep throws an exception, which is caught by the catch and executes the code in the catch. It is this kind of capture operation that the programmer can control the exit of the thread by himself. Behavior

  • If you want to exit immediately, add a break in the catch and exit;
  • If you want to wait a while before exiting, you can write the code in the catch and write break at the end, so that you can exit after execution
  • If you don't want to exit, don't add break, so after executing the catch, it will still return to while to judge, but because the interrupt does not modify the built-in flag, the loop (thread) will not exit

But if there is no method to block the thread in the thread, such as the sleep method, then interrupt will directly modify the built-in flag bit. When you return to the while to judge after the code is executed, the built-in bit has been modified, so exit the loop (thread)

Method 3 : Use the interrupted() method of the thread object to notify the end of the thread

public class ThreadDemo {
    
    
    private static class MyRunnable implements Runnable {
    
    
        @Override

        public void run () {
    
    
            // 两种方法均可以

            while ( ! Thread . interrupted ()) {
    
    
            //while (!Thread.currentThread().isInterrupted()) {
    
    

                System . out . println (Thread . currentThread (). getName ()
                        + ": 别管我,我忙着转账呢 !");
                try {
    
    
                    Thread . sleep (1000);
               } catch (InterruptedException e) {
    
    
                    e . printStackTrace ();
                    System . out . println (Thread . currentThread (). getName ()
                            + ": 有内鬼,终止交易! ");
                    // 注意此处的 break

                    break ;
               }
           }
            System . out . println (Thread . currentThread (). getName ()
                    + ": 啊!险些误了大事");
       }
   }
    public static void main (String [] args) throws InterruptedException {
    
    
        MyRunnable target = new MyRunnable ();
        Thread thread = new Thread (target , "李四 ");
        System . out . println (Thread . currentThread (). getName ()
                + ": 让李四开始转账。 ");
        thread . start ();
        Thread . sleep (10 * 1000);
        System . out . println (Thread . currentThread (). getName ()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子! ");
        thread . interrupt ();
   }
}

There are two ways for thread to receive notifications:

  • If the thread is blocked and suspended due to calling wait/join/sleep and other methods, it will be notified in the form of InterruptedException and the interrupt flag will be cleared. When InterruptedException occurs, whether to end the thread depends on the way the code in the catch is written. You can choose to ignore this Exception, you can also jump out of the loop to end the thread.
  • Otherwise, only an internal interrupt flag is set, and thread can pass Thread.interrupted() to judge that the interrupt flag of the current thread is set, clear the interrupt flag, and Thread.currentThread().isInterrupted() to judge that the interrupt flag of the specified thread is set , does not clear the interrupt flag

The difference between interrupted and isInterrupted is that the interrupted flag will be automatically cleared, that is to say, the built-in flag is originally false. If interrupt is called outside, it will change from false to true, but when it reads while(!Thread.interrupted()), Will read this true, but after reading, this flag will automatically return to false


The thread termination here in Java is relatively circumvented, and the decision is given to the thread to be terminated itself

The native thread library of the operating system, when interrupted, the caller has the right to decide

3. Thread waits for join

The order of execution between threads is completely random, depending on the scheduling of the system

We cannot determine the order in which the two threads start executing, but we can control the end of the two threads through join

public class Demo11 {
    
    
    private static Thread t1 = null;
    private static Thread t2 = null;
    public static void main(String[] args) throws InterruptedException {
    
    
        System.out.println("main begin");
        t1=new Thread(()->{
    
    
            System.out.println("t1 begin");
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("t1 end");
        });
        t1.start();
        t1.join();//让t1先执行完
        t2=new Thread(()->{
    
    
            System.out.println("t2 begin");
            try {
    
    

                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("t2 end");
        });
        t2.start();
        t2.join();//让t2执行完
        System.out.println("main end");
    }
}

运行结果:main begin
		t1 begin
		t1 end
		t2 begin
		t2 end
		main end


In this code, the main thread executes t1 first, then join waits for t1 to end, after t1 ends, the main thread starts t2, and then waits for t2 to end

The behavior of join:

  • If the waiting thread has not finished executing, block waiting
  • If the waiting thread has finished executing, it returns directly

For example, in the above code, after thread t1 is started, t1 calls join, t1 is the waiting thread, other threads have to wait for t1 to finish executing, if t2 is started, t2 calls join, main waits for t2 to end

method illustrate
public void join() Waiting for the thread to end (dead wait)
public void join(long mills) Wait for the thread to end, at most mills milliseconds
public void join(long mills.int nanos) Same but with higher precision

The third is join(100,1000) which is equivalent to waiting for 100.001ms

4. Thread sleep sleep

insert image description here

There are actually multiple linked lists for managing PCBs in the operating system kernel

Q: After writing a sleep(1000), will it run on the CPU after 1000ms?

Answer: Not necessarily. After 1000ms, just put the PCB back into the ready queue. As for when this thread can be executed on the CPU, it depends on the mood of the scheduler.

method illustrate
public static void sleep(long millis) throws InterruptedException Sleeps the current thread for millis millis milliseconds
public static void sleep(long millis,int nanos) throws InterruptedException Can sleep with higher precision

5. Get the current thread reference

method illustrate
public static Thread currentThread(); Returns a reference to the current thread object
Thread.currentThread()//哪个线程调用,就返回哪个线程的对象

Guess you like

Origin blog.csdn.net/HBINen/article/details/126586808