线程中断
- 一. 启动线程的方式
- 二. 安全中断
- 三. 线程的补充知识
- 3.1 线程常用方法和线程的状态:
- 3.2 线程的优先级概念:
一. 启动线程的方式
新启线程的方式
- 继承
Thread
类 - 实现
Runnable
接口,实际上也是通过Thread
类来进行线程的操作的
package cn.enjoyedu.ch1.base;
import java.util.concurrent.ExecutionException;
/**
*类说明:新启线程的方式
*/
public class NewThread {
/*扩展自Thread类*/
private static class UseThread extends Thread{
@Override
public void run() {
super.run();
// do my work;
System.out.println("I am extendec Thread");
}
}
/*实现Runnable接口*/
private static class UseRunnable implements Runnable{
@Override
public void run() {
// do my work;
System.out.println("I am implements Runnable");
}
}
public static void main(String[] args)
throws InterruptedException, ExecutionException {
UseThread useThread = new UseThread();
useThread.start();
UseRunnable useRunnable = new UseRunnable();
new Thread(useRunnable).start(); //这里传入的是实现Runnable接口的类,实际上也是利用了Thread进行线程的启动的
}
}
二. 安全中断
如何安全中断线程
- 不是利用
stop
这种方式,这种方式强烈禁止 - 建议不要使用
boolean
变量控制进行的中断,直接使用isInterrupted()
继承Thread
类的类如何进行安全中断:!isInterrupted()
package cn.enjoyedu.ch1.base.safeend;
/**
*类说明:如何安全中断线程
*/
public class EndThread {
private static class UseThread extends Thread{
public UseThread(String name) {
super(name); // 这里就是将name传进来,构造函数;这个是从Thread继承过来的。
}
@Override
public void run() { // 多线程的功能,里面可以写一些功能。
String threadName = Thread.currentThread().getName();
System.out.println(threadName+" interrrupt flag ="+isInterrupted());
while(!isInterrupted()){ // 这个地方如果是false的话,这里是不会执行的。就相当于如果不是中断状态的话,这里才会被执行。这里一直都在循环
//while(!Thread.interrupted()){ // 如果没有产生中断请求的话,这里是一直在执行的。直接进入下一条代码继续执行。
//while(true){
System.out.println(threadName+" is running");
System.out.println(threadName+"inner interrrupt flag ="
+isInterrupted());
}
System.out.println(threadName+" interrrupt flag ="+isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
Thread endThread = new UseThread("endThread"); // 利用构造方法进行创建线程
endThread.start();
Thread.sleep(21);
endThread.interrupt(); //中断线程,其实设置线程的标识位true
}
}
实现Runnable
接口的类如何进行安全中断: !Thread.currentThread().isInterrupted()
package cn.enjoyedu.ch1.base.safeend;
/**
*类说明:实现接口Runnable的线程如何中断
*/
public class EndRunnable {
private static class UseRunnable implements Runnable{
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
//直接调用Thread里面的currentThread().isInterrupted(),通过这种形式判断这一个进程是不是中断状态
System.out.println(Thread.currentThread().getName()
+ " I am implements Runnable.");
}
System.out.println(Thread.currentThread().getName()
+" interrupt flag is "+Thread.currentThread().isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
UseRunnable useRunnable = new UseRunnable();
Thread endThread = new Thread(useRunnable,"endThread");
endThread.start();
Thread.sleep(20);
endThread.interrupt();
}
}
阻塞方法中抛出InterruptedException
异常:
package cn.enjoyedu.ch1.base.safeend;
/**
*类说明:阻塞方法中抛出InterruptedException异常后,如果需要继续中断,需要手动再中断一次
*/
public class HasInterrputException {
private static class UseThread extends Thread{
public UseThread(String name) {
super(name);
}
@Override
public void run() {
while(!isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) { // 这里的捕捉到InterruptedException以后,会将标志位isInterrupted修改为false
System.out.println(Thread.currentThread().getName()
+" in InterruptedException interrupt flag is "
+isInterrupted());
//资源释放
interrupt(); // 再次手动的中断我们的线程:isInterrupted = true
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ " I am extends Thread.");
}
System.out.println(Thread.currentThread().getName()
+" interrupt flag is "+isInterrupted());
}
}
public static void main(String[] args) throws InterruptedException {
Thread endThread = new UseThread("HasInterrputEx");
endThread.start();
Thread.sleep(500); //这里是主线程。控制主函数里面的代码。
endThread.interrupt();
}
}
"C:\Program Files\Java\jdk1.8.0_162\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2022.2.3\lib\idea_rt.jar=63290:D:\Program Files\JetBrains\IntelliJ IDEA 2022.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\java\jdk1.8.0_162\jre\lib\charsets.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\deploy.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\access-bridge-64.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\cldrdata.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\dnsns.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\jaccess.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\jfxrt.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\localedata.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\nashorn.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\sunec.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\sunjce_provider.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\sunmscapi.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\sunpkcs11.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\ext\zipfs.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\javaws.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\jce.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\jfr.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\jfxswt.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\jsse.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\management-agent.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\plugin.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\resources.jar;C:\Program Files\java\jdk1.8.0_162\jre\lib\rt.jar;D:\AndroidTool\AndroidProject\Java04\资料&代码\资料&代码\vip-v2-concurrent\concurrent\target\classes;C:\Users\Administrator\.m2\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar" cn.enjoyedu.ch1.base.safeend.HasInterrputException
HasInterrputEx I am extends Thread.
HasInterrputEx I am extends Thread.
HasInterrputEx I am extends Thread.
HasInterrputEx I am extends Thread.
HasInterrputEx in InterruptedException interrupt flag is false
HasInterrputEx I am extends Thread.
HasInterrputEx interrupt flag is true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at cn.enjoyedu.ch1.base.safeend.HasInterrputException$UseThread.run(HasInterrputException.java:18)
Process finished with exit code 0
三. 线程的补充知识
3.1 线程常用方法和线程的状态:
start()
方法和run()
方法的区别:
start()
:线程开启的方法。执行了start()
方法才能开启线程。run()
:业务逻辑的方法。每一个线程的业务逻辑都写在里面。
package cn.enjoyedu.ch1.base;
/**
*类说明:StartAndRun在执行上的区别
*/
public class StartAndRun {
public static class ThreadRun extends Thread{
@Override
public void run() {
int i = 90;
while(i>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();
}
System.out.println("I am "+Thread.currentThread().getName()
+" and now the i="+i--);
}
}
}
public static void main(String[] args) {
ThreadRun threadRun = new ThreadRun();
threadRun.setName("threadRun");
threadRun.start();
// threadRun.run();
}
}
yield()
方法:
- 让出
CPU
的占有权,将线程从运行态转变为就绪态。 - 将让出来的
cpu
资源,操作系统将所让出来的时间片在线程之间重新进行分配。 - 只是让出
cpu
资源,但是不会让出自己的线程锁。
join()
方法:
- 使用
join()
方法可以保证两个线程可以顺序的执行。
package cn.enjoyedu.ch1.base;
import cn.enjoyedu.tools.SleepTools;
/**
*类说明:演示Join()方法的使用
*/
public class UseJoin {
static class Goddess implements Runnable {
private Thread thread;
public Goddess(Thread thread) {
this.thread = thread;
}
public Goddess() {
}
public void run() {
System.out.println("Goddess开始排队打饭.....");
try {
if(thread!=null) thread.join();
} catch (InterruptedException e) {
}
SleepTools.second(2);//休眠2秒
System.out.println(Thread.currentThread().getName()
+ " Goddess打饭完成.");
}
}
static class GoddessBoyfriend implements Runnable {
public void run() {
SleepTools.second(2);//休眠2秒
System.out.println("GoddessBoyfriend开始排队打饭.....");
System.out.println(Thread.currentThread().getName()
+ " GoddessBoyfriend打饭完成.");
}
}
public static void main(String[] args) throws Exception {
Thread lison = Thread.currentThread();
GoddessBoyfriend goddessBoyfriend = new GoddessBoyfriend();
Thread gbf = new Thread(goddessBoyfriend);
Goddess goddess = new Goddess(gbf);
//Goddess goddess = new Goddess();
Thread g = new Thread(goddess);
g.start();
gbf.start();
System.out.println("lison开始排队打饭.....");
g.join();
SleepTools.second(2);//让主线程休眠2秒
System.out.println(Thread.currentThread().getName() + " lison打饭完成.");
}
}
以下通过三种场景来对join()
进行解释:
一. 不使用join()
,仅仅goddess
和主线程
的场景:
- 可以看到,
g
线程和main线程同样是2
秒sleep()
,但是main
线程是在g
线程之前,main
线程具有优先级。 - 此时,
Thread==null
,Thread.join()
不会执行
g.start();
// gbf.start();
System.out.println("lison开始排队打饭.....");
// g.join(); //告诉主线程,您先等一下,你下面的先别忙,我先把我的执行完了,你再继续执行下面的语句。
SleepTools.second(2);//让主线程休眠2秒
System.out.println(Thread.currentThread().getName() + " lison打饭完成.");
lison开始排队打饭.....
Goddess开始排队打饭..... // 间隔2秒后
main lison打饭完成. // 因为主线程有优先级,同样的等待时间,主线程先执行
Thread-1 Goddess打饭完成.
Process finished with exit code 0
二. 使用join()
,仅仅goddess
和主线程
的场景:
- 可以看到,
g
线程和main线程同样是2
秒sleep()
,但是g线程由于在主线程代码快中加入了join()
,因此从join
开始,后面的代码都是当g
线程结束完了之后,才能分配cpu
资源给main
线程执行。 - 此时,
Thread==null
,Thread.join()
不会执行
g.start();
// gbf.start();
System.out.println("lison开始排队打饭.....");
g.join(); //告诉主线程,您先等一下,你下面的先别忙,我先把我的执行完了,你再继续执行下面的语句。
SleepTools.second(2);//让主线程休眠2秒
System.out.println(Thread.currentThread().getName() + " lison打饭完成.");
lison开始排队打饭.....
Goddess开始排队打饭..... // 停顿2秒
Thread-1 Goddess打饭完成. // 停顿2秒
main lison打饭完成.
Process finished with exit code 0
三. 使用join()
,goddess
、goddessboyfriend
和主线程
的场景:
- 可以看到,
g
线程gbf
线程和main
线程同样是2
秒sleep()
,但是g
线程由于在main
线程代码快中加入了join()
,因此从join
开始,后面的代码都是当g
线程结束完了之后,才能分配cpu
资源给main
线程执行。 - 同时,因为有
gbf
线程存在此时Thread!=null
条件成立,gbf
会执行Thread.join()
,gbf
将会在g
之前执行。 - 所以,执行完成的顺序为:
gbf > g > main
g.start();
gbf.start();
System.out.println("lison开始排队打饭.....");
g.join(); //告诉主线程,您先等一下,你下面的先别忙,我先把我的执行完了,你再继续执行下面的语句。
SleepTools.second(2);//让主线程休眠2秒
System.out.println(Thread.currentThread().getName() + " lison打饭完成.");
lison开始排队打饭.....
Goddess开始排队打饭.....
GoddessBoyfriend开始排队打饭.....
Thread-0 GoddessBoyfriend打饭完成.
Thread-1 Goddess打饭完成.
main lison打饭完成.
Process finished with exit code 0
3.2 线程的优先级概念:
.setDaemon(true)
可以设置为守护线程。- 守护线程中的
finally
不一定起作用。因为非守护线程执行完了,守护线程自动释放,不需要人为释放资源。(取决于当前操作系统给当前线程是否分配足够的时间片,完全看概率。)。 - 用户线程结束,守护线程就结束。(注意:用户线程中的
finally
一定要执行,只有守护线程中的finally
才有可能不执行。)
package cn.enjoyedu.ch1.base;
import java.util.concurrent.ExecutionException;
/**
*更多课程咨询 安生老师 QQ:669100976 VIP课程咨询 依娜老师 QQ:2470523467
*
*类说明:守护线程的使用
*/
public class DaemonThread {
private static class UseThread extends Thread{
@Override
public void run() {
try {
while (!isInterrupted()) {
System.out.println(Thread.currentThread().getName()
+ " I am extends Thread.");
}
System.out.println(Thread.currentThread().getName()
+ " interrupt flag is " + isInterrupted());
} finally {
//守护线程中finally不一定起作用
System.out.println(" .............finally");
}
}
}
public static void main(String[] args)
throws InterruptedException, ExecutionException {
UseThread useThread = new UseThread();
useThread.setDaemon(true); //设置成守护线程
useThread.start();
Thread.sleep(5);
// useThread.interrupt();
}
}