当前位置: 首页 > news >正文

手把手教你做网站7软文街

手把手教你做网站7,软文街,中国开发网站的公司,推广app用什么平台比较好线程 线程的常见属性 线程属性可以通过下面的表格查看。 •ID 是线程的唯⼀标识,不同线程不会重复 • 名称是各种调试⼯具⽤到(如jconsoloe) • 状态表示线程当前所处的⼀个情况,下⾯我们会进⼀步说明 • 优先级高的线程理论上来…

线程

线程的常见属性

线程属性可以通过下面的表格查看。
•ID 是线程的唯⼀标识,不同线程不会重复
• 名称是各种调试⼯具⽤到(如jconsoloe)
• 状态表示线程当前所处的⼀个情况,下⾯我们会进⼀步说明
• 优先级高的线程理论上来说更容易被调度到
• 关于后台线程,需要记住⼀点:JVM会在⼀个进程的所有非后台线程结束后,才会结束运⾏。
• 是否存活,即简单的理解,为 run 方法是否运⾏结束
• 线程的中断问题,下⾯我们进⼀步说明
在这里插入图片描述

线程的状态

线程状态分为New、Terminated、Runnable、Waiting、Timed_Waiting、Blocked

观测线程状态可以通过jconsole观察。

  • New 该状态下存在Thread对象,还没有调用start,系统内部PCB还未创建
  • Terminated 该状态下表示线程已终止,内部创建的PCB已经销毁,Thread对象还在
  • Runnable 该状态下表示线程正在CPU上执行,随时可以被调度。
  • Waiting 死等状态进入的阻塞
  • Timed_Waiting 带有规定时间的等待
  • Blocked 进行锁竞争后出现的阻塞状态

线程状态之间的转换图(省略版)
在这里插入图片描述

线程是否存活

在线程生命周期中,根据观察线程中的PCB是否存在。

Thread t = new Thread(()->{});

在这段代码中,线程t只是初始化了一个Thread对象,但是其中的PCB只有在执行了t.start()以后才会被创建出来。

public static void main(String[] args) {Thread t = new Thread(()->{});t.start();try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}

在上面的代码中,线程t在启动以后创建了PCB,但是因为t中代码块没有任何代码,所以线程t很快就运行结束了,内核中的线程和PCB马上就被销毁了。而在main线程中,通过sleep停止了2s,因此线程t的PCB被销毁,而t这个对象并没有被gc回收,t仍然是存在的。
在下面的代码中,我加上了t=null,通过这个方法以求解决t对象能够被gc回收。但显然是不行的,通过t=null,可能会导致t线程还没结束,t对象就为空了。

public static void main(String[] args) {Thread t = new Thread(()->{});t.start();t = null;try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}

因此,Thread给了我们一种属性:isAlive,是否存活。通过这个属性我们可以查看到线程是否存在,并对线程t进行操作。

public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{for (int i = 0; i < 5; i++) {System.out.println("hello ");}System.out.println("线程t是否存活:"+Thread.currentThread().isAlive());});t.start();Thread.sleep(3000);System.out.println("线程t是否存活:"+ t.isAlive());}

结果如下图
在这里插入图片描述

前台线程和后台线程的关系与区别

线程是并发执行的。当然,当线程多了以后,为了能够不让某些线程影响整个进程的结束,更好的利用系统资源。于是为线程设计了前台和后台两个线程方式。在前台线程中,如果本线程运行没有结束,则此时Java进程也无法结束。在后台线程中,即使该线程还处于执行阶段,当前台线程都结束以后,意味着整个Java进程即将结束。那么这时候后台线程就不得不停止执行了。
简单来说,前台线程决定了Java进程的时间,后台线程无法控制整个进程的时间,只能被迫跟着前台线程的结束而结束。
前台线程也可以是多个的,只有最后一个前台线程结束,整个Java进程才结束。

设置线程的前后台

在Java中,main线程,以及默认情况下的线程都属于前台线程。而改变线程前后台的方式可以通过修改线程前后台属性: t.setDaemon(true) 将对应线程转变为后台线程。

接下来使用一个例子进行简单演示
public class Demo1 {public static void main(String[] args) {Thread t = new Thread(() -> {while (true) {for (int i = 0;i<5;i++) {System.out.println("hello thread");}}});t.setDaemon(true);t.start();for (int i = 0; i < 5; i++) {System.out.println("hello main");}}
}

在上面的代码中,我们可以看到,理论上来说线程t应当是进入死循环不断打印"hello thread"的,但是我在线程启动之前,将t线程设置为后台线程。因此,在main线程运行结束以后,垃圾回收机制gc将main线程回收,前台线程结束,后台线程t自然也只能被迫结束。
在这里插入图片描述

线程核心操作

启动 t.start()

通过多次的练习,已经明白t.start()执行后创建线程PCB,真正创建线程并开始执行。不再过多赘述

终止 interrupt()

在Java中,终止线程不是简单的停止线程的执行。而是对线程进行提醒,提醒线程是否停止,而真正做决定的还是该线程本身。
1)通过变量控制终止线程

	private static boolean isRunning=true;public static void main(String[] args) throws InterruptedException {// boolean isRunning = true;//变量捕获Thread t2 = new Thread(()->{while (isRunning) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("t2线程被结束了");});t2.start();Thread.sleep(4000);System.out.println("控制t2线程结束");isRunning = false;}

结果如下图
在这里插入图片描述
2)使用线程的interrupt和isInterrupted方法
通过下面的代码进行解释,在这个代码块中,线程t3通过isInterrupted判断是否结束这个循环,而在main线程中,通过t.interrupt方法,将这个值修改为false,抛出RuntimeException异常,结束了当前的线程。

public static void main(String[] args) throws InterruptedException {Thread t3 = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException();//抛出异常并结束}}System.out.println("t2线程被结束了");});t3.start();Thread.sleep(3000);t3.interrupt();}

在这里插入图片描述
3)提醒线程而不终止
在下面的代码中,修改了boolean之后,线程t3并没有停止线程,而是打印出异常信息之后继续执行。
在这里出现了一个问题,为什么通过interrupt方法之后修改了boolean值,但是在线程抛出异常之后仍然在继续打印呢?
首先,interrupt方法修改了boolean值的标志位修改为true,在slee过程中,通过interrupt方法强制唤醒线程,在强制唤醒后清除了刚刚的标志位,重新修正回flase。

public static void main(String[] args) throws InterruptedException {Thread t3 = new Thread(()->{while (!Thread.currentThread().isInterrupted()) {System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace(); //打印异常信息而不结束//throw new RuntimeException();//抛出异常并结束}}System.out.println("t2线程被结束了");});t3.start();Thread.sleep(3000);t3.interrupt();}

在这里插入图片描述

等待join()

因为线程是抢占式执行的,其调度顺序在系统中是无序的。而这种无序的执行方式不在程序猿的掌控之中,因此我们希望能够通过一些方式控制这些线程。join(等待)就是其中一种方式。

  • 基本用法
    在下面的代码块中,分为main线程和t两个线程。我们可以注意到,与之前的写法其实是大差不差的,唯一区别的是在try-catch包裹下出现的t.join()方法。
    在main线程中使用t.join的作用让main线程进入阻塞等待状态,t线程执行完之后main线程才会接着往下执行。
    通过这样的方式在一定程度上解决了线程的控制问题。
public static void main(String[] args) {Thread t = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("thread end");});t.start();try {t.join();} catch (InterruptedException e) {throw new RuntimeException(e);}for (int i = 0; i < 5; i++) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("main end");}

因此我们可以看到结果如下图所示:
在这里插入图片描述

  • 多个线程的join
    在多个线程等待代码了解之前,我们必须了解的是在main线程中调用t1.join,是main线程等待t1,而与其他线程无关,main线程是不会等待其他线程的。当多线程的情况下也是这般理解的。
    在下面的代码中,存在t1和t2两个线程,在main线程中,同时调用t1.join()和t2.join() 这意味着main线程只有等t1线程和t2线程全部执行完毕以后才会往下执行。t1和t2线程各自调度执行,互不影响。 所需的时间是t1线程和t2线程运行时间较长的。
public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1 end");});Thread t2 = new Thread(() -> {for (int i = 0; i < 10; i++) {System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t2 end");});t1.start();t2.start();t1.join();t2.join();for (int i = 0; i < 10; i++) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("main end");}
  • 有限时间内等待
    在上面两个情况下,对于t.join()的方法,只有等待线程t运行结束以后才能进行下一步,属于死等状态。那么如果出现意料之外的情况,线程t无法结束,那么整个程序都会因此卡住,无法执行后续的逻辑,极大降低了系统的容错。
    因此Java提供了join带参数的两种方法。通过这两种方法,当线程超过规定时间而不结束,则主线程不再等待,继续执行下面的逻辑。
    在这里插入图片描述
    接下来简单写个demo
    在这个demo中,存在三个线程分别为t1、t2、main。在代码中我通过t1.join()让两个线程都进行阻塞状态等待线程t1结束。而对于t2,不相同的是我只让main线程等待2s,超过两秒之后,main线程不再是阻塞状态,而是执行下面的逻辑。
public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("hello t1");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1 end");});Thread t2 = new Thread(() -> {try {t1.join();} catch (InterruptedException e) {throw new RuntimeException(e);}for (int i = 0; i < 5; i++) {System.out.println("hello t2");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t2 end");});t1.start();t2.start();t1.join();t2.join(2000);//等待2s后main线程自己走了for (int i = 0; i < 5; i++) {System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("main end");}

因此代码结果如下:
在这里插入图片描述

总结

多线程有许多常见属性以及各类用法,都是需要熟练掌握的。
源码:多线程相关代码

http://www.zhongyajixie.com/news/43899.html

相关文章:

  • 国外网站设计模板百度网盘下载速度慢破解方法
  • 如何使用qq空间做推广网站应用市场
  • 文化传播公司做网站宣传好吗网络营销是什么意思?
  • 策划人网深圳网站关键词优化公司
  • 温州网约车哪个平台最好360网站seo手机优化软件
  • 怎么查看网站谁做的seochinaz查询
  • 数据库网站建设新媒体营销策略有哪些
  • 中央广播电视总台山东总站站长之家whois查询
  • wordpress七牛上传插件seo教程最新
  • 微信公众平台一定要找网站做吗狼雨的seo教程
  • 东阳市住房与城乡建设局网站网络seo哈尔滨
  • 免费申请网站12月30日疫情最新消息
  • 朋友 合同 网站制作全国疫情最新消息今天新增
  • 上海网站建设yuue域名官网
  • 网页设计一个网站搜索引擎seo排名优化
  • 做公司网站需要多简述seo的基本步骤
  • wordpress如何嵌入b站视频百度网页推广
  • 宁波高端网站建设网络广告营销方案
  • 个人独资企业的优缺点seo基础教程视频
  • 天津网络科技有限公司seo排名优化培训
  • 写作投稿网站怎么做好网站方式推广
  • 网站定制设计价目表短视频seo软件
  • 大连网站建设意动科技公司山西搜索引擎优化
  • 提取卡密网站怎么做it培训学校哪家好
  • 四川省人民政府官网投诉电话河南网站seo
  • 网站安全检测平台近几天发生的新闻大事
  • 阿里云主机做网站南京网站设计公司
  • 招商加盟网站开发百度网络营销推广
  • 做旅游网站的意义杭州seo运营
  • 石家庄制作网站公司有哪些高端营销型网站