前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >线程操作类

线程操作类

作者头像
端碗吹水
发布2020-09-23 10:37:26
6510
发布2020-09-23 10:37:26
举报

线程操作类:

线程操作类是Thread类,可以使用这个类进行线程方面的相关操作,例如获得当前线程对象,令当前睡眠,强制激活线程等等,可以直接调用静态的方法。

如何获得当前线程:

currentThread();是获得当前线程对象的方法,可以直接使用也可以将得到的对象存放到变量中,得到对象后还可以使用getName();方法得到线程对象的名称,还有getId();方法可以得到线程对象的编号,getPriority();方法则可以可以得到线程对象的优先级。

代码示例:

f18b37965265899236490f9108aa1750.png
f18b37965265899236490f9108aa1750.png

运行结果:

3d7a8b018ffb6f35d65ff81626b8b06b.png
3d7a8b018ffb6f35d65ff81626b8b06b.png

如何使线程在某个地方就结束呢:

stop();方法,从名字也看的出来,这方法就是调用后会终止线程的,这个方法会直接把线程对象销毁,来起到结束线程。一旦线程结束了,接下来的代码就不会被执行,不管是什么代码,还有需要注意的一点是:线程只有一次生命,结束之后等于死亡状态,这个“死掉”的线程是不可以再复活的,所以没有办法再继续启动的。

代码示例:

ad378f196204d15db4b6da2faae1bee8.png
ad378f196204d15db4b6da2faae1bee8.png

运行结果:

b86d6b06019839bc5c629f0ce793c1a9.png
b86d6b06019839bc5c629f0ce793c1a9.png

从结果可以看出,线程结束后的两句打印函数没有被执行

认识一下线程的状态:

State是枚举类型,使用这个类可以得到所有状态,要注意的是并不是得到某个线程对象的状态,想要得到某个线程的状态要使用那个线程对象调用getState();方法获得。

   Thread.State.NEW  新建状态

当线程对象刚刚被创建,还没有进入运行、开启的时候就是新建状态。

Thread.State.RUNNABLE 运行状态

当线程对象进入运行、开启的时候就是运行状态。

Thread.State.WAITING  无时间限制等待状态

当线程对象调用wait方法时,并且没有设置时间参数时就会进入此状态。

Thread.State.TIMED_WAITING  有时间限制的等待状态

当线程对象调用sleep方法时,并且设置时间参数后就会进入此状态。

Thread.State.TERMINATED   线程死亡状态

线程对象被销毁,线程结束时就会进入死亡状态。

Thread.State.BLOCKED  线程死锁状态

在线程同步里,两个线程陷入互相等待对方的时候就会进入线程死锁状态。

如何开启一个线程:

想要开启一个线程,首先要写一个类继承于Thread类,并且要重写run();方法,然后创建线程对象后使用对象调用start();方法来启动线程。

为什么一定要重写run();方法呢,因为线程对象在调用start方法的时候会向系统申请资源,接着线程就会进入到运行状态,线程进入到运行状态的时候会调用run方法,run方法结束后线程就会进入死亡状态。线程进入运行状态时首先调用的是run方法,做个不是很恰当的比喻就是:run方法就类似于普通类的main方法一样,运行时实际上只会执行这个方法里面的代码。所以你想要线程执行你编写的代码就必须重写run方法。

当你想给线程起一个你想出来的名字可以使用线程对象调用setName方法来设置线程的名字。

代码示例:

9beefbc63108ecc5892bb21860616588.png
9beefbc63108ecc5892bb21860616588.png

运行结果:

e06b2965d8ca91c2d8ccaa86ddfcb28b.png
e06b2965d8ca91c2d8ccaa86ddfcb28b.png

从代码的运行结果来看,有人可能会疑惑为什么main方法里的打印函数明明在最后一句,为什么会先执行?

实际上呢,问题不在于谁先执行了,首先main也是一个线程,你开启的也是一个线程,线程之间是独立并行的,至于谁的代码先执行完是要看谁跑的快,就像食堂开饭一样,先到的先打到饭后到的后打到饭,所以也是会出现main线程后面才执行完的情况的。

线程这货可不止继承Thread类这一种创建方式,线程还可以实现Runnable这个接口来创建。至于为什么还有这种创建方式,因为别忘了java只能单一继承,万一继承了其他的类又要把这个类作为线程的时候就只能使用接口的方式了,而且接口也能多实现多个。

  代码示例:

f1afcc153c5275482db5482b3b3c9d22.png
f1afcc153c5275482db5482b3b3c9d22.png

运行结果:

1997ce6bc233be52e1989f530accbcfe.png
1997ce6bc233be52e1989f530accbcfe.png

可能看到代码后,又有人会疑惑,为什么构建Thread类的时候需要将当前的类的实例对象传递给Thread的构造器?

因为在Thread的内核代码里的原理是这样的:

8f03352068a3d47d546605bbe037121e.png
8f03352068a3d47d546605bbe037121e.png

也就是说,你将对象传递过去后,这个类会将这个对象经过一系列的处理后保存到这个Thread类的属性里,所以当你在你写的类中使用Thread的对象调用run方法的时候就又会调回到你原来的类上面去,简单的理解就是调用run的时候在里面浪了一圈之后就回到你写的run方法上去了。

sleep方法:

sleep方法可以设置一个时间使线程进入睡眠状态,线程进入睡眠状态后会根据你设置的时间参数醒来。使用sleep时要知道的一点是:sleep方法是静态的,在当前的线程下不能使用这个方法来让另一个线程进入睡眠状态。

例如:A线程不能在自己的线程里使用B线程的对象来调用sleep方法,因为即便是使用B线程的对象来调用了也是A线程会进入睡眠状态并不是B线程。所以由此可知在哪个线程里遇到sleep方法哪个线程就会进入睡眠状态,即便你使用的是其他线程对象调用的也是如此。

还有一点就是:调用sleep方法线程进入睡眠状态后,如果这个线程被强制激活、叫醒了,就会抛出异常。因为你想想睡着睡着被叫醒,是个人都有起床气嘛,呸,说错了不是人是线程,但是睡到自然醒就不会有这个问题。

当线程对象进入睡眠状态,你想要在代码运行到某处的时候叫醒睡眠中的线程的话,可以使用睡眠中的线程对象调用interrupt();方法,此方法可以强制激活睡眠中的线程,但是这种激活方式就如同上面所说的会抛出异常,需要注意处理异常;

激活线程代码示例:

201b680c5a6b791ccc283b8c5c97b5eb.png
201b680c5a6b791ccc283b8c5c97b5eb.png

运行结果:

148291e1c8c66bf10d484df8264ab347.png
148291e1c8c66bf10d484df8264ab347.png

不激活线程代码示例:

cbcab66ef52ad04df0677b4e26b7d9f1.png
cbcab66ef52ad04df0677b4e26b7d9f1.png

运行结果:

6b6797caabeab018dd0a3f339293c282.png
6b6797caabeab018dd0a3f339293c282.png

主线程和子线程:

主线程是开启某个线程的线程,被这个线程开启的线程就是子线程。这个说法说起来有点绕口,换个比喻就是:例如main是一个线程,在main里开启了一个A线程,那么main就是主线程A就是子线程。

主线程会等待子线程结束才结束,也就是说子线程还有一秒没干完活,主线程就不会自己偷跑。

但是有个方法可以让主线程结束的时候就把子线程结束掉,称之为守护型线程,只要主线程结束,不管子线程是否还有代码没有执行完都强制随着主线程结束,这个方法就是setDaemon(boolean on); 使用线程对象调用此方法时给参数传递个true就代表这是个守护型线程,要注意的是这个方法一定要在start方法之前调用,在start方法之后调用是会抛异常的,因为你得在线程启动前声明这是个守护型线程。

  代码示例:

8050cba5f307622745624921c6a738bd.png
8050cba5f307622745624921c6a738bd.png

运行结果:

d9cc9bf10e29f5945152702800a2e14d.png
d9cc9bf10e29f5945152702800a2e14d.png

因为主线程先结束了,子线里的循环还没来得及进行,所以count的值为0。

join方法:

此方法的作用是等待线程结束,一般在书面上写的意思是合并线程方法,从其作用来理解成等待线程结束会好理解一些,只有等待到线程结束了,才会执行下面的代码。

这个方法可以传递一个时间参数,用来表示如果线程到指定的时间还没结束就不等了,就会继续执行下面的代码。如果不设置时间参数的话,就会一直死等到线程结束为止,才会往下执行。

  不设置时间参数的代码示例:

e5d0955f5ec99ef6532b3532137dbb52.png
e5d0955f5ec99ef6532b3532137dbb52.png

运行结果:

93a078110dfef2e6f18e7f4d48e111f6.png
93a078110dfef2e6f18e7f4d48e111f6.png

设置时间参数的代码示例:

3fd9da5a444dff1c88a1e88867825322.png
3fd9da5a444dff1c88a1e88867825322.png

运行结果:

60d8279cad28b4f844def4191a89432f.png
60d8279cad28b4f844def4191a89432f.png

使用线程优化之前的代码统计器的统计代码的速度:

线程类:

f048f0c45aa4334f37b396de01a37906.png
f048f0c45aa4334f37b396de01a37906.png
9aab2929a9205655d45d5521d7591c91.png
9aab2929a9205655d45d5521d7591c91.png

文件搜索类:

每找到一个文件就开启一个线程去统计

05148d26d80687fce856e1850c885294.png
05148d26d80687fce856e1850c885294.png
5a25fb12160d795dfb33b6062d18fd9e.png
5a25fb12160d795dfb33b6062d18fd9e.png

运行结果:

a453ee788481ed197fe168508042ddfb.png
a453ee788481ed197fe168508042ddfb.png
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-10-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档