The mystery of Thread.stop being disabled
Asked how to terminate a thread, probably most people know that you can call the Thread.stop method.
But this method is no longer recommended after jdk1.2. Why is it not recommended?
Let’s first look at the definition of this method:
@Deprecated(since="1.2") public final void stop() { @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { checkAccess(); if (this != Thread.currentThread()) { security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION); } } // A zero status value corresponds to "NEW", it can't change to // not-NEW because we hold the lock. if (threadStatus != 0) { resume(); // Wake up thread if it was suspended; no-op otherwise } // The VM can handle all thread states stop0(new ThreadDeath()); }
We can see from the code that the stop method first detects whether there is thread access permission. If you have permission, determine whether the current thread is a newly created thread. If not, then call the resume method to release the suspended state of the thread.
Finally call the stop0 method to end the thread.
Resume and stop0 are two native methods, and the specific implementation will not be discussed here.
It seems that the stop method is very reasonable and there is no problem. So why is this method unsafe?
Next let’s look at an example.
We create a NumberCounter class. This class has a safe method increaseNumber, which is used to add one to the number:
public class NumberCounter { //要保存的数字 private volatile int number=0; //数字计数器的逻辑是否完整 private volatile boolean flag = false; public synchronized int increaseNumber() throws InterruptedException { if(flag){ //逻辑不完整 throw new RuntimeException("逻辑不完整,数字计数器未执行完毕"); } //开始执行逻辑 flag = true; //do something Thread.sleep(5000); number++; //执行完毕 flag=false; return number; } }
In fact, in actual work, such a method may need to perform comparison It takes a long time, so here we simulate this time-consuming operation by calling Thread.sleep.
Here we also have a flag parameter to mark whether the increaseNumber method has been successfully executed.
Okay, next we call the method of this class in a thread and see what happens:
public static void main(String[] args) throws InterruptedException { NumberCounter numberCounter= new NumberCounter(); Thread thread = new Thread(()->{ while (true){ try { numberCounter.increaseNumber(); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); Thread.sleep(3000); thread.stop(); numberCounter.increaseNumber(); }
Here, we create a thread and wait for this thread to run for 3 seconds After that, the thread.stop method was called directly, and we found the following exception:
Exception in thread "main" java.lang.RuntimeException: The logic is incomplete and the digital counter has not been executed
at com.flydean.NumberCounter.increaseNumber(NumberCounter.java:12)
at com.flydean.Main.main(Main.java:18)
This is because of the thread.stop method The running of the thread is directly terminated, resulting in mberCounter.increaseNumber not being completed.
But this unfinished state is hidden. If you use the thread.stop method to terminate the thread, it is likely to lead to unknown results.
So, we say thread.stop is unsafe.
How to be safe
So, if the thread.stop method is not called, how can we terminate the thread safely?
The so-called safety means that the logic in the thread needs to be completely executed, not half executed.
In order to achieve this effect, Thread provides us with three similar methods, which are interrupt, interrupted and isInterrupted.
interrupt is to set the interrupt flag for the thread; interrupted is to detect the interrupt and clear the interrupt status; isInterrupted only detects the interrupt. Another important point is that interrupted is a class method that acts on the current thread. interrupt and isInterrupted act on this thread, that is, the thread represented by the instance that calls this method in the code.
interrupt is the interrupt method. Its workflow is as follows:
If the current thread instance is calling wait(), wait(long) or wait( long, int) method or the join(), join(long), join(long, int) method, or the Thread.sleep(long) or Thread.sleep(long, int) method is called in this instance and is blocking status, its interrupted status will be cleared and an InterruptedException will be received.
If this thread is blocked during an I/O operation on the InterruptibleChannel, the channel will be closed, the thread's interrupt status will be set to true, and the thread A java.nio.channels.ClosedByInterruptException exception will be received.
If this thread is blocked in java.nio.channels.Selector, the interrupt status of the thread will be set to true, and it will return immediately from the select operation .
If none of the above conditions are true, set the interrupt status to true.
In the above example, in the increaseNumber method of NumberCounter, we called the Thread.sleep method, so if the interrupt method of thread is called at this time, the thread will throw An InterruptedException.
We change the above call example to the following:
public static void main(String[] args) throws InterruptedException { NumberCounter numberCounter = new NumberCounter(); Thread thread = new Thread(() -> { while (true) { try { numberCounter.increaseNumber(); } catch (InterruptedException e) { System.out.println("捕获InterruptedException"); throw new RuntimeException(e); } } }); thread.start(); Thread.sleep(500); thread.interrupt(); numberCounter.increaseNumber(); }
Try again after running:
Exception in thread "main" Exception in thread "Thread-0" java.lang.RuntimeException: 逻辑不完整,数字计数器未执行完毕
at com.flydean.NumberCounter.increaseNumber(NumberCounter.java:12)
at com.flydean.Main2.main(Main2.java:21)
java.lang.RuntimeException: java.lang.thread.interrupt: sleep interrupted
at com.flydean.Main2.lambda$main$0(Main2.java:13)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.InterruptedException: sleep interrupted
at java.base/java.lang.Thread.sleep(Native Method)
at com.flydean.NumberCounter.increaseNumber(NumberCounter.java:17)
at com.flydean.Main2.lambda$main$0(Main2.java:10)
... 1 more
捕获InterruptedException
可以看到,我们捕获到了这个InterruptedException,并且得知具体的原因是sleep interrupted。
捕获异常之后的处理
从上面的分析可以得知,thread.stop跟thread.interrupt的表现机制是不一样的。thread.stop属于悄悄终止,我们程序不知道,所以会导致数据不一致,从而产生一些未知的异常。
而thread.interrupt会显示的抛出InterruptedException,当我们捕捉到这个异常的时候,我们就知道线程里面的逻辑在执行的过程中受到了外部作用的干扰,那么我们就可以执行一些数据恢复或者数据校验的动作。
在上面的代码中,我们是捕获到了这个异常,打印出异常日志,然后向上抛出一个RuntimeException。
正常情况下我们是需要在捕获异常之后,进行一些处理。
那么自己处理完这个异常之后,是不是就完美了呢?
答案是否定的。
因为如果我们自己处理了这个InterruptedException, 那么程序中其他部分如果有依赖这个InterruptedException的话,就可能会出现数据不一致的情况。
所以我们在自己处理完InterruptedException之后,还需要再次抛出这个异常。
怎么抛出InterruptedException异常呢?
有两种方式,第一种就是在调用Thread.interrupted()清除了中断标志之后立即抛出:
if (Thread.interrupted()) // Clears interrupted status! throw new InterruptedException();
还有一种方式就是,在捕获异常之后,调用Thread.currentThread().interrupt()再次中断线程。
public void run () { try { while (true) { // do stuff } }catch (InterruptedException e) { LOGGER.log(Level.WARN, "Interrupted!", e); // Restore interrupted state... Thread.currentThread().interrupt(); } }
这两种方式都能达到预想的效果。
The above is the detailed content of How to terminate a thread in Java. For more information, please follow other related articles on the PHP Chinese website!

Emerging technologies pose both threats and enhancements to Java's platform independence. 1) Cloud computing and containerization technologies such as Docker enhance Java's platform independence, but need to be optimized to adapt to different cloud environments. 2) WebAssembly compiles Java code through GraalVM, extending its platform independence, but it needs to compete with other languages for performance.

Different JVM implementations can provide platform independence, but their performance is slightly different. 1. OracleHotSpot and OpenJDKJVM perform similarly in platform independence, but OpenJDK may require additional configuration. 2. IBMJ9JVM performs optimization on specific operating systems. 3. GraalVM supports multiple languages and requires additional configuration. 4. AzulZingJVM requires specific platform adjustments.

Platform independence reduces development costs and shortens development time by running the same set of code on multiple operating systems. Specifically, it is manifested as: 1. Reduce development time, only one set of code is required; 2. Reduce maintenance costs and unify the testing process; 3. Quick iteration and team collaboration to simplify the deployment process.

Java'splatformindependencefacilitatescodereusebyallowingbytecodetorunonanyplatformwithaJVM.1)Developerscanwritecodeonceforconsistentbehavioracrossplatforms.2)Maintenanceisreducedascodedoesn'tneedrewriting.3)Librariesandframeworkscanbesharedacrossproj

To solve platform-specific problems in Java applications, you can take the following steps: 1. Use Java's System class to view system properties to understand the running environment. 2. Use the File class or java.nio.file package to process file paths. 3. Load the local library according to operating system conditions. 4. Use VisualVM or JProfiler to optimize cross-platform performance. 5. Ensure that the test environment is consistent with the production environment through Docker containerization. 6. Use GitHubActions to perform automated testing on multiple platforms. These methods help to effectively solve platform-specific problems in Java applications.

The class loader ensures the consistency and compatibility of Java programs on different platforms through unified class file format, dynamic loading, parent delegation model and platform-independent bytecode, and achieves platform independence.

The code generated by the Java compiler is platform-independent, but the code that is ultimately executed is platform-specific. 1. Java source code is compiled into platform-independent bytecode. 2. The JVM converts bytecode into machine code for a specific platform, ensuring cross-platform operation but performance may be different.

Multithreading is important in modern programming because it can improve program responsiveness and resource utilization and handle complex concurrent tasks. JVM ensures the consistency and efficiency of multithreads on different operating systems through thread mapping, scheduling mechanism and synchronization lock mechanism.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Dreamweaver CS6
Visual web development tools

WebStorm Mac version
Useful JavaScript development tools

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

SublimeText3 Mac version
God-level code editing software (SublimeText3)