Chapter 1 Overview of JUC

What is JUC

Java 5.0 provides the java.util.concurrent (JUC for short) package, which adds utility classes that are commonly used in concurrent programming and is used to define custom subsystems similar to threads, including thread pools, asynchronous IO and lightweight task framework. Provides an adjustable and flexible thread pool. Collection implementations designed for use in multi-threaded contexts are also provided.

  • Content involved
    • java.util.concurrent
    • java.util.concurrent.atomic
    • java.util.concurrent.locks

Why it’s important to learn about multiple threads

In terms of hardware

  • Moore's Law: Since 2003, the main frequency of CPU has no longer doubled, but multi-core has been adopted instead of faster main frequency, which is the failure of Moore's Law.
  • When the main frequency no longer doubles and the number of cores continues to increase, parallel or concurrency technology must be used to make the program faster.

In terms of software

  • Essential for interviews
  • Take advantage of multi-core processors
  • Improve program performance, high concurrency system
  • Improve program throughput, asynchronously add callbacks and other production needs

existing problems

  • Thread safety issues
  • Thread lock problem
  • Thread performance issues

Java multithreading related concepts

a lock

  • synchronized will be explained later

two and

Concurrency and Parallelism

Take dining in a restaurant as an example. Three guests came to the restaurant and there was demand for these dishes.

img

  • Serial: There is only one chef in this restaurant. If you want to satisfy the requirements of three guests, you can only cook dishes one by one. After satisfying your needs for three dishes, you can satisfy my needs for three dishes. This pattern of satisfying one by one in sequence is the serial processing method.
  • Parallel: There are three chefs in this restaurant, each chef serves his own customers, so that the needs of three customers can be met at the same time. This processing mode is parallel processing.
  • Concurrency: There is still only one chef in the restaurant, but I cooked a dish for one of the customers, and then turned to cooking for another user. It is processed according to the concept of a time slice. Each time slice may handle different things. of

If the chef cooks very fast and can produce a dish in 1 minute, then I serve a dish, and then another dish comes out 3 minutes later, then in real life, we will feel that this chef is specializing in cooking. To serve us, apply this idea to computers. We know that the processing speed of the CPU is very fast, basically the processing speed in ns. Therefore, when the CPU executes computer tasks concurrently, in our subjective consciousness , we feel that this CPU is processing tasks in parallel

Three processes

process, thread, monitor

The relationship between process and program

what is program

  • A program is a series of organized files that encapsulate various APIs of the operating system to achieve different effects (a program is a sequence of instructions, the code of the program is placed in the program segment, and the output and input data are placed in the data segment), such as QQ It's just a program

what is process

  • A process is an execution process of a program. It is an independent smallest unit for resource allocation in the system (resources refer to key system resources such as CPU and memory).
  • For example, if I have logged in to QQ twice, then in the background task manager, there will be two QQ processes, and each process is a process executed by QQ.

img

Why introduce processes

  • Because contemporary operating systems are equipped with multi-programming technology to achieve concurrent processing, multiple programs will be placed in the memory, and there will be multiple program segments and data segments. How does the operating system correctly find the corresponding programs and data segments, so the introduction Understand the concept of process (in order to enable programs to be executed concurrently and to describe and control concurrently executed programs)

The difference between process and program

  • Process is dynamic, program is static

  • Processes can execute concurrently, but programs cannot

  • There is no one-to-one correspondence between the two

  • Processes and programs are closely related: processes cannot be detached from specific programs, and programs stipulate the actions to be completed by the corresponding processes.

  • The composition is different. A process includes PCB, program segment, and data segment. A program consists of data and instruction codes.

  • A program is a static entity that contains all instructions and data. In addition to occupying disk storage space, it does not occupy system operating resources such as CPU and memory.

  • The process consists of program segments, data segments and PCB, which will occupy system running resources such as CPU and memory.

  • A program can start multiple processes to complete the task together.

example

img

进程调度算法

  • First come first serve scheduling algorithm (FCFS)
  • Short job (process) priority scheduling algorithm
  • High priority scheduling algorithm 1 Non-preemptive priority algorithm 2 Preemptive priority scheduling algorithm 3 High response ratio priority scheduling algorithm
    • Calculation of priorities for highly responsive scheduling algorithms

img

The connection between threads and processes

什么是线程

  • Modern operating systems are all multi-threaded operating systems. A thread is a subtask of a process, and a process is a lightweight process.
  • The browser process we open, and each web page we open is an independent thread, and each thread can perform a subtask.

img

为什么引入线程

  • Some processes may need to do many things "simultaneously", but traditional processes can only execute a series of programs serially (for example, when you use QQ, you log in to your account, which is equivalent to creating a process. You can type while While video chatting, these are carried out "simultaneously", but traditional processes cannot achieve such a function, so threads are introduced to speed up concurrency)
  • If the purpose of introducing processes into the OS is to enable multiple programs to execute concurrently and improve resource utilization and system throughput, then the purpose of introducing threads into the OS is to reduce the time and space spent on concurrent execution of programs. Overhead, allowing the OS to have better concurrency (allowing processes to complete multiple functions concurrently)
  • After the introduction of threads, the process is the allocation unit of system resources other than the CPU, such as printers, and memory space is allocated to the process.
  • After the introduction of threads, not only programs can be executed concurrently, but processes can also be executed concurrently, thereby improving system concurrency.

img

线程和进程的比较

  • A process is the basic unit of OS resource allocation, and a thread is the basic unit of scheduling

  • The overhead of creating and consuming processes is far greater than creating and consuming threads, and scheduling a thread is much faster than processes

  • Processes contain threads, and each process contains at least one thread (the main thread)

  • Processes are independent of each other. Different processes will not share memory space, but threads of the same process will share memory space (share the resources of the process), and threads almost do not own system resources.

  • In a multi-CPU operating system, different threads can occupy different CPUs

  • Thread switching of the same process will not cause process switching, but thread switching of different processes will cause process switching

线程的优点

  1. Creating a new thread is much cheaper than creating a new process

  2. Compared with switching between processes, switching between threads requires much less work from the operating system

  3. Threads occupy much fewer resources than processes

  4. Can make full use of the parallel number of multi-processors and take advantage of multi-core CPUs

  5. While waiting for slow I/O operations to end, the program can perform other computing tasks

  6. For computationally intensive applications, in order to run on a multi-processor system, the calculations are broken down into multiple threads.

management

  • That is Monitor (monitor), also known as lock
  • Monitor is actually a synchronization mechanism, its obligation is to ensure (only one thread can access the protected data and code at the same time)

Why introduce monitors?

insert image description here

  • Although our record-type semaphore can truly realize the four conditions of the critical section** (idle, let busy, wait for limited wait, let right wait)**, but in the above example, we know that in the consumer and producer problems , if the order of P is reversed (the mutually exclusive P operation must be implemented after the synchronous P operation), it will cause a deadlock problem, and the PV operation will be difficult to write and error-prone.
    • mutex to achieve buffer mutual exclusion
    • empty is to achieve synchronization operation for the number of cache areas
  • Therefore, the concept of monitor is proposed, which is an advanced synchronization mechanism

The composition and basic characteristics of the pipeline

composition

  • Shared data structures local to the monitor
  • A set of procedures that operate on the data structure (the procedure is treated as a function monitor, treated as a class shared data structure, treated as an attribute in the class)
  • Statement that sets initial values ​​for shared data local to the monitor
  • A monitor has a name

Basic Features

  • Data local to the monitor can only be accessed by processes local to the monitor (encapsulation idea)
  • A process can enter the monitor to access shared data only by calling a procedure within the monitor.
  • 每次仅允许一个进程在管程内执行某个内部过程(实现了互斥访问)

The monitor implements the producer-consumer problem

insert image description here

  • Mutually exclusive operations on resources are implemented by the compiler, which is responsible for realizing the mutual exclusion of each process into the tube.
  • However, the producer and consumer models still need to implement synchronization relationships. We need to use wait and signal to achieve synchronization. Our full and empty have corresponding blocking queues.

A mechanism similar to a monitor in Java

1

public class startTest {
    
    
    public static void main(String[] args) {
    
    
        Object o=new Object();
        new Thread(()->{
    
    
            synchronized (o){
    
    

            }
        },"t2").start();
    }
}
  • Synchronization in JVM is 基于进入和退出监视器对象(Monitor,管程对象)来实现的,每个对象实例都会有一个Monitor对象,
  • The Monitor object will be created and destroyed together with the Java object, and its underlying implementation is implemented by the C++ language.
  • The execution thread must first successfully hold the monitor before it can execute the method. Finally, the monitor is released when the method is completed. During the execution of the method, the thread owns the monitor, and other threads can no longer obtain the same monitor.

Asynchronous and synchronous

From the caller's perspective, if

  • You need to wait for the result to be returned before you can continue running. This is synchronization.
  • There is no need to wait for the result to be returned, and it can continue to run, which is asynchronous

design

  • Multi-threading can make method execution asynchronous (that is, don't wait forever). For example, when reading a disk file, assuming that the reading operation takes 5 seconds. If there is no thread scheduling mechanism, the CPU can't do anything in these 5 seconds. , other codes must be paused...

in conclusion

  • For example, in a project, operations such as video file format conversion are time-consuming. At this time, open a new thread to process video conversion to avoid blocking the main thread.
  • Tomcat's asynchronous servlet also serves a similar purpose, allowing user threads to process time-consuming operations and avoid blocking tomcat's worker threads
  • In the ui program, open a thread to perform other operations to avoid blocking the ui thread.

The meaning of multithreading

什么叫多线程

  • Multi-threading: Multi-threading means that a program contains multiple execution streams, that is, multiple different threads can run simultaneously in a program to perform different tasks.

Make full use of the advantages of multi-core cpu to improve operating efficiency. Imagine the following scenario where 3 calculations are performed and the results are aggregated at the end.

计算 1 花费 10 ms
计算 2 花费 11 ms
计算 3 花费 9 ms
汇总需要 1 ms
  • If it is executed serially, the total time spent is 10 + 11 + 9 + 1 = 31ms
  • But if it is a quad-core cpu, each core uses thread 1 to perform calculation 1, thread 2 to perform calculation 2, and thread 3 to perform calculation 3, then 3
  • The threads are parallel, and the time spent only depends on the running time of the longest thread, that is, 11ms and finally adding the summary time will only take 12ms

Note that multi-core cpu is needed to improve efficiency, and single-core is still executed in turn

package Lambda;
 
public class ThreadNB {
    private static final long count=10_0000_0000;
    public static void main(String[] args) throws InterruptedException {
        serial();
        concurrent();
    }
    public static void serial(){
        long start=System.nanoTime();
        long a=0;
        for (int i = 0; i < count; i++) {
            a++;
        }
        long b=0;
        for (int i = 0; i < count; i++) {
            b++;
        }
        long end=System.nanoTime();
        double allTime=(end-start)*1.0/1000/1000;
        System.out.println("串行执行所用的时间"+allTime+"ms");
    }
    public static void concurrent() throws InterruptedException {
        //并行实现20亿的累加
        long start=System.nanoTime();
        Thread thread1=new Thread(()->{
            long a=0;
            for (int i = 0; i < count; i++) {
                a++;
            }
        });
        thread1.start();//子线程进行十亿次累加
        //主线程也进行10亿次累加
        long b=0;
        for (int i = 0; i < count; i++) {
            b++;
        }
        // 等待子线程执行结束,主线程和子线程的加法操作都完成
        // 等待子线程thread执行结束才能执行下面代码
        thread1.join();//限制子线程执行完毕,才能运行下面的代码
        long end=System.nanoTime();
        double allTime=(end-start)*1.0/1000/1000;
        System.out.println("并行耗费的时间为"+allTime+"ms");
    }
}
//串行执行所用的时间955.9495ms
//并行耗费的时间为747.6655ms
  • In theory, the execution speed of concurrent execution here should be twice that of sequential execution
  • The biggest application scenario of multi-threading is to divide a large task into multiple sub-tasks (handed over to sub-threads), and multiple sub-threads execute concurrently to improve the processing efficiency of the system. For example, the 12306 system is a multi-threaded program. In fact, each of us It is a thread, and multiple people can log in to the system to buy tickets at the same time. The payment operation is a very time-consuming operation. If it is not multi-threaded, everyone has to buy tickets in order, like queuing up to buy tickets. It is very slow and has multiple threads. (For example, you can take advantage of the time to adjust the payment page to process other people's ticket purchase operations, similar to some task scenarios that require "waiting for IO", in order to allow the waiting time for IO to do some other work, you also need to use concurrent programming )

Why use multithreading (concurrent programming)

  • Improve the utilization of multi-core CPU: Generally speaking, there will be multiple CPU cores on a host. We can create multiple threads. Theoretically, the operating system can assign multiple threads to different CPUs for execution. Each CPU Executing one thread improves CPU usage efficiency. If a single thread is used, only one CPU core can be used.

  • For example, when we are shopping online, in order to improve the response speed, we need to split, reduce inventory, generate orders, etc. These operations can be split and completed using multi-threading technology. In the face of complex business models, parallel programs will be more adaptable to business needs than serial programs, and concurrent programming is better suited to this business split.

  • Simply put:

    • Make full use of the computing power of multi-core CPUs;

    • Facilitate business splitting and improve application performance

What are the disadvantages of concurrent programming?

  • The purpose of concurrent programming is to improve the execution efficiency of the program and increase the running speed of the program. However, concurrent programming does not always improve the running speed of the program, and concurrent programming may encounter many problems, such as: 内存泄漏, 上下文切换, 线程安全, 死锁etc.

in conclusion

  • Under a single-core CPU, multi-threading cannot actually improve the running efficiency of the program. It is just to be able to switch between different tasks. Different threads use the CPU in turns, so that one thread does not always occupy the CPU and other threads cannot work.

  • Multi-core CPUs can run multiple threads in parallel, but whether it can improve the running efficiency of the program depends on the situation. After careful design, splitting the tasks and executing them in parallel can certainly improve the running efficiency of the program. But not all computing tasks can be split (refer to [Amdahl's Law] below) and not all tasks need to be split. If the purpose of the task is different, it is meaningless to talk about splitting and efficiency.

  • The IO operation does not occupy the CPU, but we usually use [blocking IO] to copy files. At this time, although the thread does not use the CPU, it needs to wait for the end of the IO, and the thread cannot be fully utilized. That’s why there are subsequent [non-blocking IO] and [asynchronous IO] optimizations

How to view process threads

windows

  • Task Manager can view the number of processes and threads, and can also be used to kill processes
  • tasklist view process
  • taskkill kills the process

linux

  • ps -fe to view all processes
    • ps -fT -p <PID> View all threads of a process (PID)
  • kill kill process
  • top Press capital H to switch whether to display threads
    • top -H -p <PID> View all threads of a process (PID)

Java

  • jps command to view all Java processes
  • jstack <PID> View all thread status of a Java process (PID)
  • jconsole to view the running status of threads in a Java process (graphical interface)

Thread context switching

Because of the following reasons, the CPU no longer executes the current thread and instead executes the code of another thread.

  • When the CPU time slice of the thread is used up, the JVM temporarily gives up the CPU operation (the JVM operating system based on time slice round-robin scheduling will not let the thread permanently give up the CPU, or give up the execution right of this time slice)
  • The currently running thread enters a blocked state for some reason, such as blocking on I/O.
  • Garbage collection
  • There is a higher priority thread that needs to run
  • The current running thread ends, that is, the tasks in the run() method are completed.
  • The thread itself calls sleep, yield, wait, join, park, synchronized, lock and other methods

Context refers to the contents of CPU registers and program counters at a certain point in time, that is, the environment in which a thread (process) executes. When a Context Switch occurs, the operating system needs to save the state of the current thread and restore the state of another thread. Corresponding concepts in Java

  • It is the Program Counter Register. Its function is to remember the execution address of the next JVM instruction. It is private to the thread.
  • The status includes the program counter and information about each stack frame in the virtual machine stack, such as local variables, operand stack, return address, etc.

Example of threads A - B

  • 1. First suspend thread A and save its state in the CPU in memory.
  • 2. Retrieve the context of the next thread B in the memory and restore it in the CPU's register to execute thread B.
  • 3. When B completes execution, resume thread A according to the position pointed to by the program counter.

Frequent occurrence of Context Switch will affect performance

User threads and daemon threads

Java threads are divided into user threads and daemon threads

  • Under normal circumstances, no special configuration is required, and the default is user thread.

  • User (User) thread: runs in the foreground and performs specific tasks. For example, the main thread of the program and the sub-threads connected to the network are all user threads.

  • Daemon thread: runs in the background and serves other foreground threads . It can also be said that the daemon thread is the "servant" of the non-daemon thread in the JVM.

    • The GC garbage collection thread is the classic daemon thread
    • Once all user threads have finished running, the daemon thread will finish its work along with the JVM
  • The daemon attribute of the thread is

    • true means it is a daemon thread
    • false means it is a user thread.
public class DaemonDemo {
    
    
    public static void main(String[] args) {
    
    
        Thread t1 = new Thread(() -> {
    
    
            System.out.println(Thread.currentThread().getName()+"\t 开始运行,"
                    +(Thread.currentThread().isDaemon() ? "守护线程":"用户线程"));
            while (true){
    
    

            }
        },"t1");
        //线程的daemon属性为true表示是守护线程,false表示是用户线程
        //---------------------------------------------
        t1.setDaemon(true);
        t1.start();
        //3秒后主线程再运行
        try {
    
    
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("----------main线程运行完毕");
    }
}

Two situations

  1. Not added t1.setDaemon(true);, the default is the user thread, t1 continues to run, so the light is on
  2. A daemon thread is added t1.setDaemon(true);. When the user thread main method ends, t1 automatically exits.

As a service thread, the daemon thread does not need to continue running without a service object. If all user threads end, it means that the business operations that the program needs to complete have ended, and the system can exit. If there are only daemon threads left in the system, the Java virtual machine will automatically exit.

The setDaemon(true) method must be set before start(), otherwise an IIIegalThreadStateException exception will be reported.

JAVA thread

The Java main class name starts
the main method in the JAVA process class, which is the main thread of this class. Thread is a concept in the operating system. The operating system kernel implements mechanisms such as threads, and provides some APIs to the user layer for users to use. (such as the pthread library of Linux). The Thread class in the Java standard library can be regarded as a further abstraction and encapsulation of the API provided by the operating system

img

How to create a Java thread

  • Inherit the Thread class and override the run method
  • Override the Runnable interface and override the run method
  • Override the Callable interface and override the call method
  • Create threads using thread pool

Inherit the Thread class

  • A subclass inherits the Thread class
  • Override run method
class MyThread extends Thread{
    
    
    @Override
    public void run() {
    
    
        System.out.println("线程运行");
    }
}
public class ThreadTest {
    
    
    public static void main(String[] args) {
    
    
        MyThread myThread = new MyThread();
        myThread.start();
    }
}
// 匿名内部类写法 创建线程对象
Thread t = new Thread() {
    
    
	public void run() {
    
    
		// 要执行的任务
	}
};
// 构造方法的参数是给线程指定名字,推荐
Thread t1 = new Thread("t1") {
    
    
	@Override
	// run 方法内实现了要执行的任务
	public void run() {
    
    
		// 要执行的任务
	}
};
// 启动线程
t.start();

Use Runnable interface with Thread

Separate [thread] and [task] (code to be executed)

  • Thread represents thread
  • Runnable runnable tasks (code to be executed by the thread)
Runnable runnable = new Runnable() {
    
    
	public void run(){
    
    
		// 要执行的任务
	}
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
t.start();
// 创建任务对象
Runnable task2 = new Runnable() {
    
    
	@Override
	public void run() {
    
    
		log.debug("hello");
	}
};
// 参数1 是任务对象; 参数2 是线程名字,推荐
Thread t2 = new Thread(task2, "t2");
t2.start();
//匿名内部类写法
 Thread thread = new Thread(new Runnable() {
    
    
    @Override
    public void run() {
    
    
        System.out.println("线程运行");
     }
}, "t1");
//Lambda写法
Thread thread = new Thread(() -> System.out.println("线程运行"), "t1");
thread.start();
  • Lambda can only be used to implement functional interfaces, with only one abstract method interface, see http://t.csdn.cn/gI076 for details
  • Using Runnable makes it easier to cooperate with advanced APIs such as thread pools.
  • Use Runnable to make the task class out of the Thread inheritance system, which is more flexible
    • Composition takes precedence over inheritance

FutureTask combination Thread

  • First implement the Callable interface
  • Override the core method call method
  • Create the corresponding FutureTask class to receive the return value of Callable
  • Pass the FutureTask object into the Thread class object
FutureTask<Integer> FutureTask = new FutureTask<>(new Callable<Integer>() {
    
    
     @Override
     public Integer call() throws Exception {
    
    
         int sum = 0;
         for (int i = 0; i < 100; i++) {
    
    
            sum += i;
         }
        return sum;
     }
});
Thread thread1 = new Thread(FutureTask);
thread1.start();
System.out.println(FutureTask.get());
  • The thread that implements the Callable interface has a return value, and the return value must be received using an object of the FutureTask class.

  • Callable and Runnable both describe a "task". Callable describes a task with a return value, and Runnable describes a task without a return value

  • Callable usually needs to be used with FutureTask. FutureTask is used to save the return result of Callable. Because Callable is often executed in another thread, it is not sure when it will be executed

What is the difference between runnable and callable
? Similarities:

  • Both interfaces can be used to write multi-threaded programs and all use Thread.start() to start threads.

Main differences:

  • The run method of the Runnable interface has no return value (directly use the Thread object to receive the object of the Runnable interface);

  • The call method of the Callable interface has a return value and is a generic type. It needs to be used with a FutureTask object to obtain the results of asynchronous execution (use a FutureTask object to receive the Callable interface, and then use a Thread object to receive the FutureTask object).

  • The run method of the Runnable interface can only throw runtime exceptions and cannot capture and handle them; the call method of the Callable interface allows throwing exceptions and can obtain exception information. Note: the Callalbe interface supports returning execution results, which needs to be obtained by calling FutureTask.get(). This method It will block the main process from continuing to execute. If it is not called, it will not be blocked.

What is FutureTask

FutureTask represents a task that operates asynchronously. An object of the specific implementation class of Callable can be passed into FutureTask, and operations such as waiting to obtain the results of this asynchronous operation task, determining whether it has been completed, and canceling the task can be performed. The result can only be retrieved when the operation is completed. If the operation has not been completed, the get method will block.

  • Details will be explained later

Which thread is calling the constructor method and static block of the thread class?

  • Please remember: the construction method and static block of the thread class are called by the thread where the new thread class is located, and the code in the run method is called by the thread itself.
  • If the above statement confuses you, let me give you an example, Thread2 is new in the main function, then:
    • (1) The construction method and static block of Thread2 are called by the main thread, and the run() method of Thread2 is called by Thread2 itself.

Use thread pool

public class ThreadDemo1 {
    
    
    public static void main(String[] args) {
    
    
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.submit(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                System.out.println("线程运行");
            }
        });
    }
}
  • The knowledge points of the thread pool will be explained in detail later.

Java 中用到的线程调度算法(Java implements preemption, and Java uses the thread counter in the JVM to implement thread scheduling)

Time-sharing scheduling model and preemptive scheduling model.

  • The time-sharing scheduling model means that all threads take turns to obtain the right to use the CPU, and the time slice of the CPU occupied by each thread is evenly distributed. This is also easier to understand.
  • The thread scheduling used by Java uses preemptive scheduling. Threads in Java will allocate CPU time slices to run according to priority, and the higher the priority, the higher the priority. However, high priority does not mean that it can occupy the execution time slice alone. It may be the priority. The higher the priority, the more execution time slices will be obtained. On the contrary, the lower priority will be allocated less execution time but will not be short of execution time.

The difference between run and start

start() starts a new thread and 在新的线程runs the code in the run method

  • The start method only makes the thread ready , and the code inside may not run immediately (the CPU time slice has not yet been allocated to it). The start method of each thread object can only be called once. If called multiple times, an IllegalThreadStateException will occur.
  • new A Thread, the thread enters the new state. Calling the start() method will start a thread and enter the ready state. When CPU resources are allocated, it can start running (running state). start() will perform the corresponding preparation work of the thread, and then automatically execute the content of the run() method, truly realizing multi-threaded operation. There is no need to wait for the run method body code to be executed when calling the start() method, and you can directly continue to execute other codes;
public class ThreadDemo2 {
    
    
    public static void main(String[] args) {
    
    
        new Thread(()->{
    
    
            System.out.println(Thread.currentThread().getName()+"开始运行");
        },"t1").start();
    }
}
//t1开始运行
public class ThreadDemo2 {
    
    
    public static void main(String[] args) {
    
    
        Thread thread = new Thread(() -> {
    
    
            System.out.println(Thread.currentThread().getName() + "开始运行");
        }, "t1");
        thread.start();
        thread.start();
    }
}
t1开始运行
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Thread.java:708)
	at com.lsc.day10.ThreadDemo2.main(ThreadDemo2.java:17)

run() The method that will be called after the new thread starts

  • If the Runnable parameter is passed when constructing the Thread object, the run method in the Runnable will be called after the thread starts, otherwise no operation will be performed by default. But you can create a subclass object of Thread to override the default behavior
  • The run() method is in this thread. It is just a function in the thread, not multi-threaded. If you call run() directly, it is equivalent to calling an ordinary function. If you use the run() method directly, you must wait for the run() method to execute before executing the following code, so there is still only one execution path, and there is no multi-threading at all. Characteristics,
public class ThreadDemo2 {
    
    
    public static void main(String[] args) {
    
    
        Thread thread = new Thread(() -> {
    
    
            System.out.println(Thread.currentThread().getName() + "开始运行");
        }, "t1");
        thread.run();
    }
}
//main开始运行

Guess you like

Origin blog.csdn.net/qq_50985215/article/details/131178847