Article directory
First, the common construction method of Thread
method | illustrate |
---|---|
Thread() | Create thread object |
Thread(Runnable target) | Create thread objects using Runnable objects |
Thread(String name) | Create a thread object and name it |
Thread(Runnable target,String name) | Use Runnable objects to create thread objects and name them |
Regarding the first two methods, I used them in the previous thread creation introduction.
There are basically two ways to create a thread:
- Create a
继承自 Thread 类
subclass, override the run method in Thread, and call the start method- Create a
实现 Runnable 接口
class that overrides the run method in Thread. Create a Thread instance, set the instance of the class that implements the Runnable interface written by yourself, and call the start method
Constructors three and four just add a parameter named thread object on the basis of the previous two construction methods, which is convenient for programmers to debug.
Code (take construction method 4 as an example):
public class func7 {
public static void main(String[] args) {
Thread thread = new Thread(() ->{
while (true) {
System.out.println("This is my Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"myThread");
//此处用 lambda 表达式代替 Runnable 实例,更加简洁,添加了一个参数指定thread线程的名字
thread.start();
while (true) {
System.out.println("my main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
jconsole
Programmers can visually view the threads created here through the tools that come with the JDK
step one:
After running the program, find your own jdk path -> bin -> jconsole.exe
Step 2: Double-click the exe file. Select Local Processes, where Java processes are listed. We can see our program func7, click on it. In the menu bar, select the thread column
Step 3: View thread information
On the left side, you can select the thread to be viewed. You can see the main thread main and the newly created thread myThread. If there is no renaming operation, the newly created thread name will be called Thread-0, Thread-1, which is not convenient to view. .
The right side shows the state of the thread at the moment it was read, and the stack trace shows where the code was executed.
2. Common properties of Thread
Attributes | method |
---|---|
ID | getId() |
name | getName() |
state | getState() |
priority | getPriority() |
Whether it is a background thread | isDaemon () |
Is it alive | isAlive() |
Is it interrupted | isInterrupted() |
explain:
-
The unique identifier of the thread is
线程 Id
-
名称
It is reflected in the above case, which provides convenience for debugging -
状态
Indicates the current situation of the thread. In the above case, the thread enters the blocked state because the sleep method is called. -
优先级
Indicates the difficulty of the thread being scheduled, higher ones are easier to be scheduled to -
judgment
是否为后台线程
. If it is a background thread, then the background thread will not affect the end of the java process; if it is a non-background thread, the JVM will wait until all non-background threads are executed before ending the operation, so it will affect the end of the total process -
是否存活
Is the method to determine whether the thread still exists. When a Thread instance object is created, the thread is not necessarily created, and the start method needs to be called to actually create the thread. When the run method in the thread is executed, the thread ends and is destroyed, and the created instance object has not been destroyed and recycled. so,创建出的实例对象和线程的生命周期是不完全相同的
In the thread's state, states other than
NEW
and are aliveTERMINATED
Code:
public class func8 {
public static void main(String[] args) {
Thread t = new Thread(()->{
for (int i = 0;i < 5;i ++) {
System.out.println("新线程~");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"newThread");
System.out.println("新线程状态:" +t.getState());
//创建了对象,没创建线程
t.start();
System.out.println("新线程状态:" +t.getState());
//创建了线程
System.out.println("新线程Id:"+t.getId());
System.out.println("新线程名称:"+t.getName());
System.out.println("新线程是否为后台线程:" + t.isDaemon());
System.out.println("新线程是否被中断:" + t.isInterrupted());
System.out.println("新线程优先级:" + t.getPriority());
System.out.println("主线程名称:"+Thread.currentThread().getName());
while (t.isAlive()) {
} //当t线程还存在时,主线程就搁这儿循环着,直到线程结束
System.out.println("新线程状态:" +t.getState());//线程结束
}
}
result:
3. Create a thread
Creating an object of the Thread class does not mean that the thread is created start() 方法才是真正的在操作系统内部创建一个新的线程
. By overriding the run method to describe the tasks that need to be executed, multi-threaded operation is truly realized.
Fourth, interrupt the thread
Method 1: 手动设置标志位
, as a condition for interrupting the thread
public class func9 {
private static Boolean flag = false;//手动设置的标志位 flag
public static void main(String[] args) {
Thread t = new Thread(() -> {
while (!flag) {
//flag 为真时停止循环
System.out.println("myThread");
try {
Thread.sleep(1000);//打印一次,阻塞一秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();//创建了线程 t
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
//等3秒后,在主线程中将 flag 的值改成 true,从而使线程t循环条件不成立
}
}
Method Two:使用 Thread 实例中的标志位
public class func10 {
public static void main(String[] args) {
Thread t = new Thread() {
@Override
public void run() {
//通过 isInerrupted()判断标志位是否为true,为true说明线程要退出
while (!this.isInterrupted()) {
System.out.println("my Thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//System.out.println("完善工作");
//break;
}
}
}
};
t.start();//创建新的线程
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.interrupt();
//t线程运行3秒后,通过 interrupt() 方法将标志位设置为 true
}
}
result:
It can be seen that when the flag bit is set to true after 3 seconds, and it is hoped that the t thread is interrupted and exited, the result is only an InterruptedException exception.
In fact, when the interrupt method is called, if the thread is in the ready state, it will directly modify the flag in the thread; if it is in the blocked state, it will cause an InterruptedException (because the sleep method is called, it is blocking, and the result is forcibly called woke up)
But after receiving the signal of interrupting the thread, an exception occurred, it just simply printed the exception, and did not respond to the exception, so the t thread continued to loop, as if the signal of interrupting the thread was just a reminder that the thread hit Just a log is done, as if you didn't hear it.
In fact, there is a reason for such a mechanism. If the interrupt method is called, the thread will be interrupted when it says it is interrupted. It is very unreasonable. At this time, it is not known where the thread is executing. , how to do the finishing work, it is up to the thread to decide when it will be destroyed
Therefore, we need to complete the work after catching the InterruptedException exception, and then jump out of the loop through break to end the thread
方法二和方法一相比更加好
. Because after the interrupt flag in method 1 is modified, even if it is sleeping at the time, the current sleep time will be over, and the next round of judgment will be made, and then the thread will be interrupted. Method 2 Even in sleep, after receiving the interrupt signal, it will be woken up immediately, and the interrupt information will be received more timely.
result:
Five, thread waiting
Determines the join() 方法
thread execution order (mainly controls the order of ending threads).
public class func11 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0;i < 3;i ++) {
System.out.println("my Thread~~");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
//t1.join();
for (int i = 0;i < 3;i ++) {
System.out.println("my main!!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
result:
When the join method is not called, the main thread and the t1 thread are concurrent, and the result output is alternate. After calling the join method, the main thread will block and wait, and the content after the join method will not be executed until the t1 thread is executed.
For the join method without parameters, the condition for waiting for the end is that the t1 thread ends, and if it does not end, it will continue to die; this method can also take parameters, and the waiting time can be specified by parameters.
6. Get the thread reference
In the thread code, you need to obtain the instantiated object of the Thread class corresponding to the current thread to perform more operations.
Method 1: Pass 继承 Thread 类创建的线程
, you can this
get
The second method in the above interrupted thread is to obtain information about whether the current instance is interrupted through this.isInterrupted().
If the method of creating a thread is changed to the method of creating a Runnable instance, the current run method is not a method of the Thread class, and this points to a Runnable, so there is no way to obtain a Thread instance, and there is no way to use the methods in it.
Method 2: Through Thread 类的 currentThread() 方法
, which thread calls this method, the instance object of which thread is returned
Seven, thread sleep
This method is often introduced in the front, that issleep 方法
Once the sleep method is called, the thread will block and wait, and the waiting time depends on the specified parameters
The operating system is scheduled in units of threads, each thread corresponds to a PCB, and these PCBs are organized through a doubly linked list
When the operating system schedules the PCB, 就绪队列
it selects a PCB to execute on the CPU. When the executing thread calls the sleep method, the PCB will be moved to the 阻塞队列
middle. When the sleep time is up, it will return to the ready queue. , ready to be executed
The join method will also generate blocking waiting. Just like the example of thread waiting, after the main thread executes the join method, it will go to the blocking queue and wait for the corresponding t1 thread to complete the execution before returning to the ready queue and ready to be executed. preparation
Eight, thread status
From the code case of the previous common attributes of Thread, it can be seen that the state of the thread is not only ready and blocked, but even blocking is divided into several blocking types
//线程的状态是一个枚举类型 Thread.State
//打印 Java 线程中的所有状态
public class func13 {
public static void main(String[] args) {
for (Thread.State state : Thread.State.values()) {
System.out.println(state);
}
}
}
result:
NEW
: Indicates that the object of the Thread class is created, but the thread has not been created, that is, the start method has not been calledRUNNABLE
: ready stateBLOCKED
: The state while waiting for the lock (look forward to the next blog on thread safety)WAITING
: Triggered by the wait method (look forward to the next blog)TIMED_WAITING
: Generated by the sleep methodTERMINATED
: The thread has been executed, but the object of the Thread class still exists and has not been destroyed
!