Home  >  Article  >  Java  >  How to understand threads in java

How to understand threads in java

王林
王林forward
2023-04-29 22:01:051170browse

How to understand threads in java

Thread is an execution path within a program. The main method we are familiar with is actually a single execution path. If there is only one execution path in the program, then the program is a single execution path. Threaded programs; since there is a single thread, there will also be multi-threading. The literal meaning can be understood as "the technology of multiple execution processes on software and hardware relative to a single thread". The advantage of multi-threading is to improve the utilization of the CPU Rate. In a multi-threaded program, when one thread must wait, the CPU can run other threads instead of waiting, greatly improving the efficiency of the program.

Creation of multi-threads

Method 1: Inherit the Thread class

Method 1 creation process:

  • Define a subclass MyThread Inherit the thread class java.lang.Thread and override the run() method;

  • Create an object of the MyThread class;

  • Call the thread object The start() method starts the thread (the run() method is still executed after startup);

    public class ThreadDemo01 {
        public static void main(String[] args) {
            MyThread myThread1 = new MyThread();
            myThread1.start();
            for (int i = 0; i < 3; i++) {
                System.out.println("主线程正在执行~~");
            }
        }
    }
    class MyThread extends Thread{
        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println("子线程正在执行~~");
            }
    
        }
    }
    //输出结果(不唯一):
    //主线程正在执行~~
    //主线程正在执行~~
    //主线程正在执行~~
    //子线程正在执行~~
    //子线程正在执行~~
    //子线程正在执行~~
  • There are two threads executing in the above code, which are the main thread and thread of the main method. The child thread started by calling start() on object mythread. But why is the output result not unique? The reason is that CPU preemption will occur between the two threads during execution, and whoever seizes it first will execute first.

So why don’t we directly use the thread object to call the run() method? If run() is called directly, it is just a normal calling method, that is, a single thread, while the start() method is used to start child threads, so that multi-threading can occur.

Method 1 Advantages and Disadvantages:

  • Advantages: Simple coding;

  • Disadvantages: The thread class has inherited Thread and cannot be inherited Other classes are not conducive to expansion;

Method 2: Implement the Runnable interface

Method 2 creation process:

1. Define a thread task class MyRunnable Implement the Runnable interface and override the run() method;

2. Create the MyRunnable object;

3. Hand the MyRunnable task object to Thread for processing;

4. Call the thread The start() method of the object starts the thread;

Thread constructor method
public Thread (String name) You can specify a name for the current thread
public Thread (Runnable target) Encapsulates the Runnable object to become a thread object
public Thread (Runnable target, String name) Encapsulate the Runnable object as a thread object and specify the thread name
public class ThreadDemo02 {
    public static void main(String[] args) {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target);
        thread.start();
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程正在执行~~");
        }
    }
}
class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("子线程正在执行~~");
        }

    }
}
//输出结果(不唯一):
//主线程正在执行~~
//子线程正在执行~~
//子线程正在执行~~
//子线程正在执行~~
//主线程正在执行~~
//主线程正在执行~~

This code The difference from the first method is that the MyRunnable task object needs to be encapsulated in Thread, and the other places are basically unchanged.

Advantages and disadvantages of method two:

Advantages: The thread task class only implements the interface, and can continue to inherit the class and implement the interface, which is highly scalable;

Disadvantages: One more layer of programming Object packaging, if the thread has execution results, it cannot be returned directly.

Next, we also use the Runnable interface (anonymous inner class form) to realize the creation of multi-threads:

1. Create a Runnable anonymous inner class object;

2. Leave it to Thread for processing;

3. Call start() of the thread object to start the thread;

//正常版:
public class ThreadDemo01 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("子线程正在执行~~");
                }
            }
        });
        thread.start();
        for (int i = 0; i < 3; i++) {
            System.out.println("主线程正在执行~~");
        }
    }
}

//lambda简化版:
new Thread(()-> {
                for (int i = 0; i < 3; i++) {
                    System.out.println("子线程正在执行~~");
                }
        }).start();

In essence, this method does not have much difference, it is just a thread that needs to be created. object, while the other is multi-threaded through anonymous inner classes. And this block of code can also be streamlined through lambda expressions. I wonder if you are still impressed by this knowledge point? If you forget, you can read this article: How to understand lambda expressions in Java - Streamlined

Method 3: Implement the Callable interface

After learning the previous two ways to create multi-threads In the future, we will find that there is a problem: 1. The rewritten run() method cannot directly return results; 2. It is not suitable for business scenarios that need to return thread execution results. Therefore, we need a third way to solve these problems.

Creation process of method three:

1. Define a class to implement the Callable interface, override the call() method, and encapsulate what needs to be done;

2. Use FutureTask to convert Callable The object is encapsulated into a thread task object;

3. Hand the thread task object to Thread for processing;

4. Call the start() method of Thread to start the thread and execute the task;

5. After the thread execution is completed, obtain the task execution result through the get() method of FutureTask.

##Method nameDescription##public FutureTask(Callable call)public V get() throws Exception
public class ThreadDemo03 {
    public static void main(String[] args) throws Exception {
        MyCallable myCallable = new MyCallable();
        FutureTask<String> futureTask = new FutureTask<>(myCallable);
        Thread thread = new Thread(futureTask);
        thread.start();
        int sum= 0;
        for (int i = 0; i < 3; i++) {
            sum+=i;
        }
        System.out.println(sum);
        String s =futureTask.get();
        System.out.println(s);
    }
}
class MyCallable implements Callable<String > {
    @Override
    public String call(){
        int sum=0;
        for (int i = 0; i < 3; i++) {
            sum+=i;
        }
        return "子线程计算结果:"+sum;
    }
}
//输出结果:
//3
//子线程计算结果:3

方式三优缺点:

优点:

线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;

可以在线程执行完毕后去获取 线程执行的结果;

缺点:

编码复杂一点;

总结

Encapsulate the Callable object into a FutureTask object
Get the result returned by the thread executing the call method
方式 优点 缺点
继承Thread类 编程比较简单,可以直接使用Thread类中的方法 扩展性较差,不能再继承其他的类,不能返回线程执行的结果
实现Runnable接口 扩展性强,实现该接口的同时还可以继承其他的类 编程相对复杂,不能返回线程执行的结果
实现Callable接口 扩展性强,实现该接口的同时还可以继承其他的类,可以得到线程的执行结果 编程相对复杂

常用方法

Thread获取和设置线程名称

方法名称 说明
String getName() 获取当前线程的名称,默认线程名称是Thread-索引
void setName(String name)

将此线程更改为指定的名称,通过构造器也可以设置线程名称

简单地通过一段代码让大家能够清晰地了解这个代码该如何使用:

public class ThreadDemo04 {
    public static void main(String[] args) throws Exception {
        thread thread1 = new thread();
        thread1.setName("1号子线程");
        thread1.start();
        thread thread2 = new thread();
        thread2.setName("2号子线程");
        thread2.start();
    }
}
class thread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(this.getName()+"正在执行任务"+i);
        }
    }
}
//输出结果:
//2号子线程正在执行任务0
//1号子线程正在执行任务0
//2号子线程正在执行任务1
//1号子线程正在执行任务1
//2号子线程正在执行任务2
//1号子线程正在执行任务2

Thread类的线程休眠方法

方法名称 说明
public static void sleep(long time) 让当前线程休眠指定的时间后再继续执行,单位为毫秒
public class ThreadDemo05 {
    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
            if (i==3){
                Thread.sleep(5000);
            }
        }
    }
}
//输出结果:
//1
//2
//3
//在输出过3以后,等待5秒之后再进行输出
//4

The above is the detailed content of How to understand threads in java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete