论多线程之中断篇

news2025/2/5 9:53:08

线程中断

  • 一. 启动线程的方式
  • 二. 安全中断
  • 三. 线程的补充知识
    • 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线程同样是2sleep(),但是main线程是在g线程之前,main线程具有优先级。
  • 此时,Thread==nullThread.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线程同样是2sleep(),但是g线程由于在主线程代码快中加入了join(),因此从join开始,后面的代码都是当g线程结束完了之后,才能分配cpu资源给main线程执行。
  • 此时,Thread==nullThread.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()goddessgoddessboyfriend主线程的场景:

  • 可以看到,g线程gbf线程和main线程同样是2sleep(),但是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();
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/103214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式:数据处理指令详解

文章目录数据处理指令的特点数据处理指令的汇编格式数据处理指令-指令表(1)ADD、ADC、SUB、SBC、RSB和RSC(2)AND、ORR、EOR和BIC(3)MOV和MVN(4)CMP和CMN(5&am…

如何下载及安装BIGEMAP GIS Office

如何下载及安装BIGEMAP GIS Office 发布时间:2018-01-17 版权: 本产品支持主流winodws操作系统(xp sp3,vista,windows 7,windows 8及windows 10 11), 可通过访问Bigemap官网(BIGEMAP-卫星地图_高清卫星地图制图软件_…

791068-69-4,肾素的FRET底物

FRET substrate for renin. excitation at 340 nm, emission at 490 nm.肾素的FRET底物。激发波长为340 nm,发射波长为490 nm。 编号: 182722中文名称: Renin Substrate 1英文名: Renin Substrate 1CAS号: 791068-69-4单字母: H2N-R-E(Edans)-IHPFHLVIHT-K(Dabcyl)-…

PDF如何加密码保护?分享PDF加密的简单方法

PDF 通常是只读的,但如果收件人有特定的编辑软件,它们仍然可以修改,因此当您发送或共享 PDF 文档时,您可能希望使用密码对其进行保护。这样,未经您的许可,任何人都无法读取文件。 如何使用密码保护 pdf 文档…

什么是SD-WAN,它如何改变传统网络?

近年来,网络的构建、管理和运行方式发生了重大变化。许多 IT 管理员现在正在用更高级的网络概念和策略取代传统的网络组件和传统技术。例如,他们越来越依赖网络容器化、自动化、软件定义网络 (SDN) 和云计算等概念来简化网络。 这…

网络安全和信息化条例

神经网络架构搜索 定义内涵 神经网络架构搜索是为给定数据集自动找到一个或多个架构的任务,这些架构将为给定 的数据集生成具有良好结果的模型,其本质是在高维空间的最优参数搜索问题。 技术背景 深度学习模型的使用越来越大众化,在很多行…

数据处理指令

目录 一、指令 1.1 数据处理指令:数学运算、逻辑运算 1.1.1数据搬移指令 1.1.2机器码 1.1.3立即数 1.1.4数据运算指令基本格式 1.1.5加法指令 1.1.6减法指令、逆向减法指令、乘法指令 1.1.7位运算(逻辑运算) 1.1.8格式扩展 1.1.9数据运算指令对条…

面试官:Spring Bean的生命周期,你知道吗?

小熊学Java网站:https://javaxiaobear.gitee.io/,每周持续更新干货,建议收藏! bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean 被销毁,可以总结为以下七个阶段: 处理名称&…

Aosp系统编译定制系统签名

商业化产品,如果使用默认的签名,一是不安全,而是显得没啥技术。就连谷歌官方也说了,不建议使用testkey作为最终发布版的key,因此,定制系统签名就派上用场了。 具体使用方法谷歌给了一个大致的说法,我们可以在aosp的自述文件中找到,位置位于build\target\product\secur…

建议收藏:数字后端笔试题,含解析

能力归能力,面试归面试,你永远不会知道面试官抛出来的会是什么样的问题。 经历了无数的笔试面试之后,发现数字IC的笔试面试还是有很对共通之处和规律可循的。 之前芯博士为大家分享了一些数字IC面试题,有不少小伙伴私信我&#…

医药企业数字化转型加剧安全风险,“三个关键举措”筑牢数据安全基石

今天,越来越多的医药企业正在探索和寻求数字化手段,赋能“研、产、供、销”各流程,实现生产效率提升。但在数字化过程中,数据安全相较以往也更加严峻,数据泄露频发,形势堪忧。《2021数据泄露成本报告》中&a…

微服务框架 SpringCloud微服务架构 微服务面试篇 54 微服务篇 54.4 Nacos如何避免并发读写冲突问题?

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 微服务面试篇 文章目录微服务框架微服务面试篇54 微服务篇54.4 Nacos如何避免并发读写冲突问题?54.4.1 Nacos 服务端源码54 微服…

leetcode 324场周赛

第三题 2508. 添加边使所有节点度数都为偶数 连接一条边,一定会让两个点的奇偶性改变。最多连接两条边,最多有四个点的奇偶性改变。所以超过了四个点为奇数点,就不可能了。 并且,由于一次改变两个,奇数点的个数一定是…

[附源码]Nodejs计算机毕业设计酒店管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

Mybatis之类型转换器TypeHandler的初步了解及具体使用方法

一、TypeHandler简介 1、什么是TypeHandler? 简介:TypeHandler(类型转换器)在mybatis中用于实现 java类型 和 JDBC类型 的相互转换。mybatis使用 prepareStatement 来进行参数设置的时候,需要通过 TypeHandler 将传入的…

ABAP MESSAGE消息类的创建以及调用方法。

消息类的类型一共分为六种,分别如下表所示 TYPE描述使用效果是否终止事务A(Abortion)终止在PUPUP画面显示是I(Information)信息在PUPUP画面显示否E(Error)错误在状态栏显示是W(Warning)警告在状态栏显示否S(Success)成功在次画面显示否X(Exit)退出在强制终止的画面…

大数据培训Impala之优化

大数据培训Impala之优化 尽量将StateStore和Catalog单独部署到同一个节点,保证他们正常通行。 通过对Impala Daemon内存限制(默认256M)及StateStore工作线程数,来提高Impala的执行效率。 SQL优化,使用之前调用执行计…

SEO优化的策略_网站seo策略

现在SEO优化成为了每一个企业进行网络营销策划的重要命题,如何做好SEO优化更是企业经常在思考的问题,SEO优化做得好,不仅可以减少企业推广的费用,更是有效的提高了推广的效果,一个好的SEO优化策略应该如何完成呢?应该从以下5点做好网站seo策略。 SEO优化策略1.确定目的 …

MySQL 数据库 - 索引与事务

文章目录1.索引1.1 优缺点1.2 使用2.事务2.1 事务的使用2.2 四大特性2.2.1 原子性2.2.2 隔离性1.索引 索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。 可以对表中的一列或多列创建索引,并指定索引的类型,各类索引有各自的数据结…

[附源码]计算机毕业设计Node.jsX工厂电影网站(程序+LW)

项目运行 环境配置: Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境:最好是Nodejs最新版,我…