Write in front
We have learned the basic knowledge of the process and know that a process needs to apply for resources from memory to run. These are the basis for us to learn today's knowledge.
thread
The process needs to apply for resources to run and release resources to end. Once down, the operating system is acceptable. But if it's too many times, I don't think anyone can afford it. Therefore, intelligent human beings have proposed a concept called Thread. The so-called Thread has the same function as the process. Sometimes we also call it "lightweight process". However, it has the following advantages.
- A thread does not need to open up and release resources. It exists in a process and shares this resource with this process.
- A process can contain one or more threads.
In Linux, our process is also represented by PCB. We find that the last pid in the figure below is the same as the first pid and belongs to the same process. It can be considered that these two threads occupy the same space. Note that the operating system does not recognize processes and threads, but only PCBs. Creating a process / thread is creating a PCB. We can also think of a process as a thread.
Thread and process relationship
This is a classic interview question. We must know it.
- A process can contain one or more threads
- Each process has an independent memory space (virtual address space), which is shared by the threads contained in the process
- Process is the basic unit of space allocated by the operating system, and thread is the basic unit of scheduling and execution of the operating system.
Threads and processes share the same piece of resources, including the following aspects
- Memory (variable)
- File (later)
Relationship between thread and code
A thread is the execution flow of a code, which we won't understand first.
Multiprocess and multithreading
As we said earlier, the development and destruction of threads do not require the participation of space, so threads are better than processes to a certain extent. We want the computer to execute as fast as possible, so there are two ways. Let's take an example. Suppose there are 100 here 🦃, Our goal is to eat these 100 🦃. How can we improve the speed of eating chicken?
- Multi process
- Multithreading
Multi process
We let two funny old fellow iron come to eat chicken separately, give each old fellow iron a house, 50 persons per person. 🦃, Here is to eat more chicken. We have two sets of tables, two rooms, that is, two resources have been opened up, and two old fellow iron can not see each other how much they ate, which is the process is isolated.
Multithreading
Multithread is a bit of a waste of resources. Can we let two funny old fellow eat chicken in the same room? This is multithreading.
We just created a funny old fellow and did not open up new resources.
Too many threads
We hope that the faster the better, but if the thread speed is too much, there will be some problems.
- Too many threads, frequent scheduling and too much overhead
- Thread unsafe
- If one thread in a process has an exception and the operating system does not see it, other threads may also have an exception
Too many threads, frequent scheduling, and too much overhead can lead to the squeeze of the old fellow.
The safety may be reduced. Two old fellow iron may have seen the same chicken thigh, they may fight.
A thread in a process is abnormal and it doesn't see it. Other threads may also be abnormal. Some old fellow iron may be unhappy, it can't grab the table and lift the table.
Code demonstration
Having said so many theories, we need to practice through code. Here I use Java. In Java, we can use the object of Thread class to represent the object of the operating system. If PCB is the way the operating system describes threads, Thread is the way the code describes threads
Create a thread
We create a process in the following ways.
//Thread is a class in the standard library // In common methods, we inherit this class, //Override run method class MyThread extends Thread { @Override public void run() { System.out.println("hello bit"); } } public class TestDemo { public static void main(String[] args) { Thread thread = new MyThread(); thread.start(); } }
Compare thread start(); And thread run();
We may feel confused. I used thread before run(); You can also get the above results. Why use thread start(); And?, What's the difference?
- thread.start(); A thread will be created to share the same resource with the process where the main method is located
- thread.run() did not create a new thread
You may have some doubts here, but don't be careful. Our following code may solve some of your doubts
class MyThread extends Thread { @Override public void run() { while (true) { System.out.println("hello Thread"); try { Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU } catch (InterruptedException e) { e.printStackTrace(); } } } } public class TestDemo { public static void main(String[] args) { Thread thread = new MyThread(); //thread.start(); thread.run(); while (true) { System.out.println("hello main"); try { Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU } catch (InterruptedException e) { e.printStackTrace(); } } } }
We use thread run();
We use thread start();
Other ways to create threads
We have other ways to create threads. The essence of these creation is the same. We create a PCB through the Thread class. The difference is only the difference of Java syntax
- A Runnable interface is used to describe a task, and the run method needs to be rewritten
- Inherit Thread, rewrite run, use anonymous inner classes, and write Simpler Syntax, which is referred to as "syntax sugar". The readability of great people is not low
- Inherit Runnable, override run, and use anonymous inner classes
- Use a lambda expression to represent the task to be performed
Runnable interface
class MyThread implements Runnable{ @Override public void run() { } } public class TestDemo { public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); //Taking an instance as a parameter is essentially the same as the first method, which tells the thread what the task is } }
Inherit Thread, override run, and use anonymous inner classes
public class TestDemo { public static void main(String[] args) { //It is equivalent to creating an internal class that inherits Thread Thread thread = new Thread() { @Override public void run() { //task } }; }
Inherit Runnable, override run, and use anonymous inner classes
public class TestDemo { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { } }); } }

Use a lambda expression to represent the task to be performed
Lambda is essentially an anonymous function. Since methods and classes cannot be separated in Java, we make lambda an interface, which is a very simple way
public class TestDemo { public static void main(String[] args) { Thread thread = new Thread(()->{ while (true) { System.out.println("hello Thread"); try { Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU } catch (InterruptedException e) { e.printStackTrace(); } } }); } }
View Thread
Can we take a look at the threads created by ourselves? JDK is allowed. There is a jconsole in JDK that can help us. Of course, IDEA is also possible. Jconsole plays a great role. When the program we write crashes, we can check it through jconsole
class MyThread extends Thread { @Override public void run() { while (true) { System.out.println("hello Thread"); try { Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU } catch (InterruptedException e) { e.printStackTrace(); } } } } public class TestDemo { public static void main(String[] args) { Thread thread = new MyThread(); //thread.start(); thread.run(); while (true) { System.out.println("hello main"); try { Thread.sleep(1000);//Let this thread sleep for a period of time and temporarily transfer it away from the CPU } catch (InterruptedException e) { e.printStackTrace(); } } } }
Run thread run();
We can find that there are many threads, the first of which is the main thread. Other threads are built-in. We don't care
Run Thread start();, Got a Thread
Advantages of multithreading
We use multithreading to make the CPU execute faster. Let's take an example.
If we want to add 100 million times to the numbers a and B respectively, we can compare the time difference between using single thread and multithreading
public class TestDemo { public static long count = 1000000000; /** * serial */ public static void serial() { long begin = System.currentTimeMillis(); int a = 0; int b = 0; for (int i = 0; i < count; i++) { a++; } for (int i = 0; i < count; i++) { b++; } long end = System.currentTimeMillis(); System.out.println("serial time = " + (end - begin)); } /** * Concurrent */ public static void multiThread() { long begin = System.currentTimeMillis(); Thread t1 = new Thread() { @Override public void run() { int a = 0; for (int i = 0; i < count; i++) { a++; } } }; Thread t2 = new Thread() { @Override public void run() { int b = 0; for (int i = 0; i < count; i++) { b++; } } }; t1.start(); t2.start(); try { t1.join(); // Thread blocking t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("multiThread() time = " + (end - begin)); } public static void main(String[] args) { serial(); multiThread(); } }
We will find that the parallel type is about half of the serial type, but it will be more than half, because the thread also takes some time to run
Recognize Thread class
We didn't know a lot about Thread just now. Now let's open the last chapter of this blog. What methods and properties are there in the Thread class. We can take a look at some of the source code in IDEA. The following is only a part. We certainly won't learn so much. It's common to learn only a part
Construction method
Thread provides many construction methods. Let's take a look
Construction method | explain |
---|---|
Thread() | Assign a new Thread object. |
Thread(String name) | Assign a new Thread object. Let's give this object a name |
Thread(Runnable target) | Assign a new Thread object. |
Thread(Runnable target,String name) | Assign a new Thread object. |
Property & get method
As above, we also see common methods
attribute | Acquisition method | explain |
---|---|---|
ID | getId() | ID is the identifier of a thread, and the indicator of different threads is different |
name | getName() | Get the name we set for the thread. If not, it is Thread-N(N is a constant) |
state | getState() | Auxiliary calling thread |
priority | getPriority() | And the PCB in the core are not exactly the same |
Whether background thread | isDaemon() | The created thread is not a background thread by default |
Is it alive | isAlive() | Whether the PCB in the core is still there |
Is it interrupted | isInterrupted() | Determine whether the thread is interrupted |
getId()
Each thread has its own ID, similar to an ID card We can check through the code
public class TestDemo4 { public static void main(String[] args) { Thread t1 = new Thread("First thread") { @Override public void run() { } }; Thread t2= new Thread() { @Override public void run() { } }; System.out.println(t1.getId()); System.out.println(t2.getId()); } }
getName()
Why give a name to Thread? It's mainly to facilitate debugging. If there are too many Thread names, giving a name can help us quickly find the Thread we want to debug
public class TestDemo { public static void main(String[] args) { Thread t1 = new Thread("First thread") { @Override public void run() { } }; Thread t2= new Thread() { @Override public void run() { } }; Thread t3= new Thread() { @Override public void run() { } }; System.out.println(t1.getName()); System.out.println(t2.getName()); System.out.println(t3.getName()); } }
getState()
Threads and processes are the same. There is a certain state. Is the thread started, or is the thread waiting? These are the state of the thread. getState() can get the state of the thread at this time
getPriority()
This is similar to the priority of a process. There may be multiple thread PCBs in a process. The priority determines which PCB will be scheduled first
isDaemon()
We need to know this about background threads. The JVM will not end until all non background threads of a process end
class MyThread extends Thread { @Override public void run() { System.out.println("hehhehhe"); } } public class TestDemo { public static void main(String[] args) { MyThread myThread = new MyThread(); System.out.println(myThread.isDaemon()); } }
isAlive()
isInterrupted()
isInterrupted() can determine whether the thread is interrupted