多线程2(常用的方法:join、interrupt、currentThread、isAlive、setDaemon...)
常用的方法:
1、join()
方法:
join()
方法:
join()
方法:执行该方法的线程进入阻塞状态,直到调用该方法的线程结束后再由阻塞状态转为就绪状态。
示例:
package venus;import java.util.Date;public class Test {public static void main(String[] args) {TimeThread timeThread = new TimeThread();//创建时间线程timeThread.start();//启动时间线程,进入就绪状态CountThread countThread = new CountThread(timeThread);//创建计数线程countThread.start();//启动计数线程,进入就绪状态}
}class CountThread extends Thread{TimeThread timeThread;public CountThread(TimeThread timeThread){this.timeThread = timeThread;}@Overridepublic void run(){for (int i=0; i<5 ; i++){System.out.println("计数###"+i);if(i == 2){try {timeThread.join();/*此处是计数线程执行该方法,所以进入阻塞状态;时间线程调用该方法,所以直到该时间线程结束后,计数线程再由阻塞状态转为就绪状态*/} catch (InterruptedException e) {e.printStackTrace();}}}}
}class TimeThread extends Thread{@Overridepublic void run(){for (int i=0; i<5 ; i++){System.out.println("计数$$$"+i+" "+new Date());}}}
结果:
计数###0
计数###1
计数###2
计数$$$0 Sun Feb 07 15:59:11 GMT+08:00 2021
计数$$$1 Sun Feb 07 15:59:11 GMT+08:00 2021
计数$$$2 Sun Feb 07 15:59:11 GMT+08:00 2021
计数$$$3 Sun Feb 07 15:59:11 GMT+08:00 2021
计数$$$4 Sun Feb 07 15:59:11 GMT+08:00 2021
计数###3
计数###4
👆 上例中,在TimeThread
类中的run()
方法里加System.out.println("计数$$$"+i+" "+new Date());
后面的new Date()
是为了让其负担更重,延后执行,能,没有别的意思。
👆 当计数线程执行到i = 2
时,由于执行了join()
方法,所以进入阻塞状态,让调用join()
方法的时间线程执行结束后,才由阻塞状态进入就绪状态准备执行。
2、interrupt()
方法:
interrupt()
方法:
interrupt()
方法:结束线程在调用Object类的wait()方法或该类的join()方法、sleep()方法过程中的阻塞状态,并在调用wait()、join()和sleep()方法处产生InterruptedException异常。
示例:
package venus;import java.util.Date;public class Test {public static void main(String[] args) {TimeThread timeThread = new TimeThread();timeThread.start();CountThread countThread =new CountThread(timeThread);countThread.start();try {Thread.sleep(15000);//15秒} catch (InterruptedException e) {e.printStackTrace();}//计数线程调用`interrupt()`方法countThread.interrupt();}
}class CountThread extends Thread{TimeThread timeThread;public CountThread(TimeThread timeThread){this.timeThread = timeThread;}@Overridepublic void run(){for (int i=0; i<3 ; i++){if (i == 1){try {timeThread.join();} catch (InterruptedException e) {System.out.println("计数线程提前结束阻塞状态");}}System.out.println("计数线程:"+i);}}
}
class TimeThread extends Thread{@Overridepublic void run(){for (int i=0; i<3; i++){System.out.println("时间线程:"+new Date());try {sleep(10000);//10秒} catch (InterruptedException e) {e.printStackTrace();}}}
}
结果:
计数线程:0
时间线程:Sun Feb 07 16:47:46 GMT+08:00 2021
时间线程:Sun Feb 07 16:47:56 GMT+08:00 2021
计数线程提前结束阻塞状态
计数线程:1
计数线程:2
时间线程:Sun Feb 07 16:48:06 GMT+08:00 2021
👆 我们由上面的join()
方法可知计数线程执行join()
方法,进入阻塞状态,应该等到调用join()
方法的时间线程执行结束后才转入就绪状态准备执行,但由于15秒过后,计数线程调用了interrupt()
方法,所以其阻塞状态被迫终止,直接进入就绪状态。
3、currentThread()
方法:
currentThread()
方法:
currentThread()
方法:返回当前正在执行的线程对象。(也就是说 哪个线程执行了该方法,就是那个线程对象)
下面我们来看四个面试题(稍微改动了一下,便于观察),深入了解一下:
示例1:
package venus;public class Test {public static void main(String[] args) {Thread thread = new TimeThread();//创建时间线程对象System.err.println(thread);thread.start();//启动时间线程,进入就绪状态}
}class TimeThread extends Thread{public TimeThread(){super("时间线程");//意思就是给要创建的线程起个名字}@Overridepublic void run() {Thread thread = Thread.currentThread();System.out.println(thread);}
}
👆 答案:
👆 分析:
(上面的System.err.println(thread);
把out
改为err
仅仅为了让结果显示的颜色不一样,便于观察分析,没有别的意思。)我们可以看到Test
类中 是TimeThread
类创建的对象,所以变量thread
指代时间线程
毫无疑问。下面的run()
方法里的currentThread()
方法是由TimeThread
类创建的时间线程执行的,所以此时的变量thread
指代时间线程
。
拓展:
上述结果:
Thread[时间线程,5,main]
第一个参数是线程名
,第二个参数是线程优先级
,第三个参数是线程组名
示例2:
package venus;import java.text.SimpleDateFormat;
import java.util.Date;public class Test {public static void main(String[] args) {new TimeThread().start();//创建时间线程并启动}
}class TimeThread extends Thread{public TimeThread(){super("时间线程");}@Overridepublic void run() {printTime();}public void printTime(){Thread thread = Thread.currentThread();String time = new SimpleDateFormat("HH:mm:ss").format(new Date());System.out.println(thread.getName()+",当前时间:"+time);}
}
👆 答案:
👆 分析:
上面是TimeThread
类创建的时间线程
执行了currentThread()
方法,所以结果就是时间线程
。
示例3:
package venus;public class Test {public static void main(String[] args) {TimeThread timeThread = new TimeThread();//创建时间线程System.err.println("########"+timeThread);timeThread.start();//启动时间线程,进入就绪状态timeThread.run();}
}class TimeThread extends Thread{public TimeThread(){super("时间线程");}@Overridepublic void run() {Thread thread = Thread.currentThread();System.out.println("@@@@@@@@"+thread);}
}
答案:
分析:
刚开始是由TimeThread
类创建的时间线程
,所以刚开始变量thread
指代时间线程
;
接着启动时间线程
,但主程序里timeThread.run()
执行run()
方法,也就是此时是主线程
执行了currentThread()
方法,所以此时的变量thread
指代主线程
;
进入就绪状态的时间线程
开始执行run()
方法,也就执行了currentThread()
方法,所以此时的变量thread
指代时间线程
。
示例4:
package venus;public class Test {public static void main(String[] args) {TimeThread timeThread = new TimeThread();//创建时间线程System.err.println("########"+timeThread);timeThread.start();//启动时间线程timeThread.main();}
}class TimeThread extends Thread{public TimeThread(){super("时间线程");}@Overridepublic void run() {main();}void main(){Thread thread = Thread.currentThread();System.out.println("@@@@@@@@"+thread);}
}
答案:
分析:
刚开始是由TimeThread
类创建的时间线程
,所以刚开始变量thread
指代时间线程
;
接着启动时间线程
,但主程序里timeThread.main()
执行main()
方法,也就是此时是主线程
执行了currentThread()
方法,所以此时的变量thread
指代主线程
;
进入就绪状态的时间线程
开始执行run()
方法,也就执行了currentThread()
方法,所以此时的变量thread
指代时间线程
。
4、isAlive()
方法:
isAlive()
方法:
isAlive()
方法:判定该线程是否处于就绪、运行或阻塞状态,如果是则返回true,否则返回false。
示例:
package venus;public class Test {public static void main(String[] args) {Thread thread = Thread.currentThread();new PrintThread(thread).start();//创建打印线程并启动System.out.println("main线程状态:"+thread.isAlive());}
}class PrintThread extends Thread{private Thread thread;public PrintThread(Thread thread){this.thread = thread;}@Overridepublic void run() {try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.err.println("main线程状态:"+thread.isAlive());}
}
结果:
分析:
当打印线程
受到sleep(1000)
阻塞时,程序一定会先执行main()
方法中的输出语句,此时会输出true;
当打印线程
阻塞状态结束,此时的主线程
肯定已经结束了,所以主线程
此时已经死了,所以输出false。
5、setDaemon()
方法:
setDaemon()
方法:
setDaemon()
方法:用于将一个尚未调用线程start()
方法的线程设置为守护线程。
- 守护线程会随着最后一个非守护线程的终止而终止;
- 进程中所启动的其他非守护线程不会随着某一个非守护线程的结束而结束;
- 进程随着最后一个非守护线程的结束而结束。
(非守护线程 也叫 时间线程)
示例:
package venus;public class Test {public static void main(String[] args) {CountThread countThread = new CountThread();countThread.setDaemon(true);//此时设置计数线程为守护线程countThread.start();try {Thread.sleep(10);//延长主线程的存活时间} catch (InterruptedException e) {e.printStackTrace();}}
}class CountThread extends Thread{@Overridepublic void run() {int i=0;while (true){System.out.println("计数:"+i);i++;}}}
结果:
分析:
我们发现当设置计数线程
为守护线程
时,启动后就会执行下去,当主线程(非守护线程)
结束时才会结束。
5、其它方法:
void start()
:使该线程开始启动,Java虚拟机负责调用该线程的run()
方法。多次启动一个线程是非法的。void sleep(long millis)
:Thread类静态方法,线程进入阻塞状态,在指定时间(单位为毫秒)到达之后进入就绪状态,而非立即进入执行状态。void yield()
:静态方法,当前线程放弃占用CPU资源,回到就绪状态(即从Running → Runnable),使其它优先级不低于此线程的线程有机会被执行。(该方法不是很可靠,因为它只是把正在执行的线程拉回到就绪状态,但就绪状态的线程采取的是抢占式)void setPriority(int newPriority)
:设置当前线程的优先级,线程优先级越高,线程获得执行的次数越多,Java线程的优先级用整数表示,取值范围是 1 ~ 10,Thread类有以下三个静态常量:
1、static int MAX_PRIORITY
最高优先级值为10;
2、static int NORM_PRIORITY
默认优先级值为5;
3、static int MIN_PRIORITY
最低优先级值为1.
注意:
同一个线程类创建的多个线程,线程优先级越高的线程执行次数极有可能越多;但是不同线程类创建的线程,线程优先级越高,执行次数不一定越高,这与run()
方法的代码复杂度有关。
int getPriority()
:获得当前线程的优先级
相关文章:
Oracle总结第二篇【视图、索引、事务、用户权限、批量操作】
前言 在Oracle总结的第一篇中,我们已经总结了一些常用的SQL相关的知识点了…那么本篇主要总结关于Oralce视图、序列、事务的一些内容… 在数据库中,我们可以把各种的SQL语句分为四大类… (1)DML(数据操纵语言ÿ…

物联网应用介绍
•物联网的研究背景(概念 | 本质 | 特征 | 发展现状)物联网是新一代信息技术的高度集成和综合运用,已成为全球新一轮科技革命与产业变革的核心驱动和经济社会绿色、智能、可持续发展的关键基础与重要引擎。国家十三五规划纲要明确提出“积极推…

Oracle使用手册(三)---存储过程与触发器
--存储过程/**//*--1.过程的语法结构--参见:http://newland.cnblogs.com/archive/2006/04/05/367531.html--2.执行存储过程begin 存储过程名;end;--创建好的存储过程可以被任何程序调用*/--3.带参数的存储过程/**//* 参数类型 在PL/SQL过程中,可以有3种类型的…

数据结构之【线性表】(顺序表、链表的基本操作实现)
概念线性表:是N个数据元素的有限序列。 顺序表:用一组地址连续的存储单元依次存储【线性表 】的数据元素。(区别于有序表:表中的数据元素存在非递增或非递减有序) 链表:用一组任意的存储单元来存储【线性表…

基于android的天气预报的设计与实现
目录 应用开发技术及开发平台介绍应用需求分析应用功能设计及其描述应用UI展示①开发技术: 本系统是采用面向对象的软件开发方法,基于Android studio开发平台,以Android作为本系统的开发语言实现音乐播放器预定的需求功能。 ②平台介绍 硬件平…

敏捷开发有感!
http://sd.csdn.net/n/20060913/94713.html1.我们最优先要做的是通过尽早的,持续的交付有价值的软件来使客户满意。有一篇文章分析了对于公司构建高质量产品方面有帮助的软件开发实践,其中一个实践表明尽早的交付具有部分功能的系统和系统质量之间具有很…

ng 表单提交验证
http://www.runoob.com/try/try.php?filenametry_ng_validate 转载于:https://www.cnblogs.com/alvin553819/p/7127226.html

Infragistics NetAdvantage 2006 Volume 2 CLR 2.0曲折安装
上个月看到Infragistics NetAdvantage 2006 Volume 2 CLR 2.0(新特性)新鲜出炉,就一直想安装试用。昨天qq上得知已经有人在使用了,赶紧google一个down下来。经过漫长下载等待,满怀希望安装,哪想到快完成的时候居然报错,…

数据结构之【栈】的基本操作C语言实现
引题: 很多人都把【栈】描述成【弹匣】,但我总感觉有点不恰当,因为弹匣从上端【装弹】之后,子弹总是在匣的上层;而元素【进栈】之后,总在栈的下面。 我觉得还是描述成【从下往上向书箱里一层…

编码小记(未整理-持续更新)
----------------基本概念-------------------------------一.位: 计算机存储信息的最小单位,称之为位(bit),音译比特,二进制的一个“0”或一个“1”叫一位。 二.字节 字节(Byte)是一…

使用locate 的正则查询 查找所有main.c
locate支持正则查询的功能, 只需输入locate -r 正则表达式 即可。 现在我想查找所有main.c怎么做? 打开终端,输入shell: locate -r main.c$ PS:$表示结束字符串结束。转载于:https://www.cnblogs.com/the-one/p…

My Favorites
AJAX "Atlas" Control Toolkit HomePage "Atlas" Client Class Library "Atlas" Server Class Library ASP.NET AJAX Roadmap http://www.ajaxian.com 被成为AJAX第一站 . http://www.ajaxmatters.com/ 不仅有讨论XMLHttpRequest 的文…

数据库事务初探
使用事务级别要慎重: 因为事务级别越高,数量越多、限制性更强的锁就会被运用到数据库记录或者表中。同时,更多的锁被运用到数据库和它们的覆盖面越宽,任意两个事务冲突的可能性就越大。 如果有一个冲突(例如两个事务试图获取同一个…

数据结构之【队列】的基本操作C语言实现
直接上图: 循环队列的声明: 0、循环队列的声明 循环队列的基本操作: 1、InitQueue(&Q)(构造一个空队列) 2、DestroyQueue(&Q)(销毁队列Q) 3、ClearQueue(&Q)(清空队列Q&…

在python3环境安装builtwith模块
1、安装命令: pip install builtwith 如果在命令行提示如下错误: Fatal error in launcher: Unable to create process using " 使用如下命令: python3 -m pip install builtwith 2、导入模块会出现错误提示: 原因࿱…

kettle组件-输出
1:删除连接数据库:新建连接数据库,或者应用转换中已经定义好的数据库。目标模式:指什么现在还不明确,集群模式?子服务器模式?--要写入数据的表的Schema名称。允许表名中包含“.”是很重要的。目…

NGOSS的一点简单概念
NGOSS(Next Generation Operational Support Systems)是由TMF(Tele Management Forum)提出的,他用于电信领域,是构建下一代OSS/BSS系统的框架。TMF提供了技术中立构架(TNA)作为NGOSS…

Windows Mobile 5.0 设备的目录变化
自定义铃声的默认两个存放位置:1. Application Data\Sounds (不是Storage下的Application Data了)。2. 外存储设备的根目录。

第二周期的第一次站立会议
今天:对这一阶段的任务进行了分配,我就自己的任务内容搜集了一些资料,尝试了编程。明天:继续进行编程。遇到的问题:编程方面有些许的困难。转载于:https://www.cnblogs.com/guantianhuan/p/10051436.html

常见的函数式编程模型
1.闭包(Closure) 闭包的概念 可以保留局部变量不被释放的代码块,被称为一个闭包。 闭包的特点:函数嵌套函数、内部函数可以引用外部函数的参数和变量、参数和变量不会被垃圾回收机制收回 // 创建一个闭包 function makeCounter() …

Ubuntu下安装和配置Redis
找到 /ect/redis/redis.conf 文件修改如下:注释掉 127.0.0.1 ,如果不需要远程连接redis则不需要这个操作。使用客户端向 Redis 服务器发送一个 PING ,如果服务器运作正常的话,会返回一个 PONG。默认情况下,Redis服务器不允许远程访问,只允许本机访问,所以我们需要设置打开远程访问的功能。执行sudo apt-get install redis-server 安装命令。查看 redis 是否启动,重新打开一个窗口。停止/启动/重启redis。

自学笔记——1.Pyhton保留关键字
Python保留关键字python保留的关键字如下python保留的关键字如下 and del from None True as elif global nonlocal try assert else if not while break except import or with class False in pass yield continue finally is raise def for lambda…

人的一生有三件事不能等
人的一生有三件事不能等人的一生有三件事不能等 第一是“贫穷” 贫穷不能等,因为一但时间久了,你将习惯贫穷,到时不但无法突破自我,甚至会抹杀了自己的梦想,而庸庸碌碌的过一辈子。。。。。。 第二是“梦想” 梦想不能…

安装部署中的数据库打包和快捷方式启动浏览器
前一段时间,因为工作的需要,学习了一些.net的部署。在打包的过程中遇到了几个问题:<?XML:NAMESPACE PREFIX O />1、 数据库脚本打包,如何修改Web.config文件中的数据联接2、 数据库脚本中的方法和视图打包时要注意的问题…

Windows下安装和配置Redis
下载版本Redis-x64-5.0.14.1.zip。(可能需要开代理)

python练习册 每天一个小程序 第0004题
1 #-*-coding:utf-8-*- 2 __author__ Deen 3 4 题目描述:任一个英文的纯文本文件,统计其中的单词出现的个数。5 参考学习链接:6 re http://www.cnblogs.com/tina-python/p/5508402.html#undefined7 collections http://blog.csdn.…

xxxxxxx
xxxxxxxxxxxxxxxx转载于:https://www.cnblogs.com/pythonClub/p/10054454.html

自学笔记——2.字符串的切片、遍历、查找字符
一、字符串的切片 字符串的部分片段或者子集称为切片操作,所有字符串的切片操作是通过方括号([ ])实现的,语法:[n : m : s] 会返回一个子字符串,从索引值n到n-1之间,以s为步进,即&a…

【EXLIBRIS】随笔记 011
随 笔 记 <十一> 持这种观点的人一个是Dr. Johnson,另一个是西方文化影响更加根深蒂固的Reverend,似乎英文字母(Indian-European family)那种“抽象的、率意独断”的符号(Wai-lim Yip语)才是最基本的…

Ubuntu搭建Spark运行环境
前言 因为之前研究的方向是分布式系统,重点放在了Hadoop分布式文件系统上。现如今,社会对机器学习的需求势如破竹。为了调整研究方向,而且不抛弃原本的研究成果,研究反向便从分布式系统转为分布式机器学习算法(刚起步&…