多线程-Thread类的常用方法和生命周期

news/2024/11/25 15:38:17/

Thread类的常用结构

构造器

  • public Thread():分配一个新的线程对象。
  • public Thread(String name):分配一个指定名字的新的线程对象。
  • public Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接口中的run()方法。
  • public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。

常用方法系列1

  • public void run():此线程要执行的任务在此处定义代码。
  • public void start():导致此线程开始执行;Java虚拟机调用此线程的run方法。
  • public String getName():获取当前线程名称。
  • public void setName():设置该线程名称。
  • public static Thread currentThread():返回对当前正在执行的线程对象的引用。在Thread子类中就是this,通常用于主线程和Runnable实现类。
  • public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
  • public static void yield(): yield只是让当前线程暂停一下,让系统的线程调度器重新调度一次,希望优先级与当前线程相同或更高的其他线程能够获得执行机会,但是这个不能保证,完全有可能的情况是,当某个线程调用了yield方法暂停之后,线程调度器又将其调度出来重新执行。

常用方法系列2

  • public final boolean isAlive(): 测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。

  • void join(): 等待该线程终止。

    void join(long millis): 等待该线程终止的时间最长为millis毫秒。如果millis时间到,将不再等待。

    void join(long millis,int nanos): 等待该线程终止的时间最长为millis毫秒 + nanos 纳秒。

  • public final void stop(): 已过时,不建议使用。强行结束一个线程的执行,直接进入死亡状态。run()即刻停止,可能会导致一些请理性的工作得不到完成,如文件,数据库等的关闭。同时,会立即释放该线程所持有的所有的锁,导致数据得不到同步的处理,出现数据不一致的问题。

  • void suspend() / void resume(): 这两个操作就好比播放器的暂停和恢复。二者必须成对出现,否则非常容易发生死锁。suspend()调用会导致线程暂停,但不会释放任何锁资源,导致其他线程都无法访问被它占用的锁,直到调用resume()。已过时,不建议使用。

常用的方法系列3

每个线程都有一定的优先级,同优先级线程组成先进先出队列(先到先服务),使用分时调度策略。优先级高的线程采用抢占式策略,获得较多的执行机会。每个线程默认的优先级都与创建它的父线程具有相同的优先级。

  • Thread类的三个优先级常量:
    • MAX_PRIORITY(10):最高优先级
    • MIN_PRIORITY(1): 最低优先级
    • NORM_PRIORITY(5):普通优先级,默认情况下main线程具有普通优先级。
  • public final int getPriority(): 返回线程优先级
  • public final void setPriority(int newPriority): 改变线程的优先级,范围在[1——10]之间。

练习:获取main线程对象的名称和优先级。

声明一个匿名内部类继承Thread类,重写run方法,在run方法中获取线程名称和优先级。设置该线程优先级为最高优先级并启动该线程。

一、线程的常用结构
1. 线程中的构造器
- public Thread():分配一个新的线程对象。
- public Thread(String name):分配一个指定名字的新的线程对象。
- public Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接口中的run()方法。
- public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。2.线程中的常用方法:
> start():1)启动线程 (2)调用线程的run()
> run(): 将线程要执行的操作,声明在run()中。
> currentThread(): 获取当前执行代码对应的线程。
> getName(): 获取线程名
> setName(): 设置线程名
> sleep(long millis): 静态方法,调用时,可以使得当前线程睡眠指定的毫秒数
> yield(): 静态方法,一旦执行此方法,就释放CPU的执行权
> join(): 在线程a中通过线程b调用join(),意味着线程a进入阻塞状态,直到线程b执行结束,线程a才结束阻塞状态,继续执行
> isAlive(): 判断当前线程是否还存活过时方法:
> stop(): 强行结束一个线程的执行,直接进入死亡状态。不建议使用
> void suspend() / void resume() : 可能造成死锁,所以也不建议使用3.线程的优先级:
getPriority(): 获取线程的优先级
setPriority(): 设置线程的优先级。范围是[1,10]Thread类内部声明的三个常量:
- MAX_PRIORITY(10):最高优先级
- MIN_PRIORITY(1): 最低优先级
- NORM_PRIORITY(5):普通优先级,默认情况下main线程具有普通优先级。二、线程的生命周期

常用方法练习:

package thread.demo02;public class EvenNumberTest {public static void main(String[] args) {//测试1PrintNumber t1 = new PrintNumber("线程1:偶数");t1.setName("线程1(修改):偶数");//修改上面的线程名"线程1:偶数"为"线程1(修改):偶数"t1.setPriority(Thread.MAX_PRIORITY);//注意不是哪个优先级高就先运行完哪个线程,是CPU几率更高优先来调用优先级高的线程。// 打印出来发现还是主线程第一个运行,因为现在都是多核CPU,这是概率问题。t1.start();//测试setName()Thread.currentThread().setName("主线程");Thread.currentThread().setPriority(Thread.MIN_PRIORITY);for (int i = 1; i <= 100; i++) {if (i % 2 == 0){System.out.println(Thread.currentThread().getName() + " 优先级为:" +Thread.currentThread().getPriority() + ": " + i);}//            if (i == 20){
//                try {
//                    t1.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }}//测试isAlive()
//        System.out.println("线程1(修改):偶数 是否存活?" + t1.isAlive());//测试2PrintNumber1 p = new PrintNumber1();Thread t2 = new Thread(p,"线程2:奇数");t2.start();}
}//测试1:-public Thread(String name):分配一个指定名字的新的线程对象。
class PrintNumber extends Thread{//无参构造public PrintNumber(){}//分配一个指定名字的新的线程对象。public PrintNumber(String name){super(name);}@Overridepublic void run() {for (int i = 1; i <= 100; i++) {//测试sleep()
//            try {
//                Thread.sleep(1000);//设置了1000毫秒也就是一秒,对应的这个线程1一秒钟执行一下,直到结束
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }if (i % 2 == 0){System.out.println(Thread.currentThread().getName() + " 优先级为:" +Thread.currentThread().getPriority() + ": " + i);}//测试yield()
//            if (i % 20 == 0){
//                Thread.yield();
//            }}}
}//测试2:- public Thread(Runnable target,String name):分配一个带有指定目标新的线程对象并指定名字。
class PrintNumber1 implements Runnable{@Overridepublic void run() {for (int i = 1; i <= 100; i++) {if (i % 2 != 0){System.out.println(Thread.currentThread().getName() + " 优先级为: " +Thread.currentThread().getPriority() + " " + i);}}}
}

多线程的生命周期

Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下一些状态:

JDK1.5之前:5种状态

线程的生命周期有五种状态:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、死亡(Dead)。CPU需要在多条线程之间切换,于是线程状态会多次在运行、阻塞、就绪之间切换。

在这里插入图片描述

1.新建

当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态。此时它和其他Java对象一样,仅仅由JVM为其分配了内存,并初始化了实例变量的值。此时的线程对象并没有任何线程的动态特征,程序也不会执行它的线程体run()。

2.就绪

但是当线程对象调用了start()方法之后,就不一样了,线程就从新建状态转为就绪状态。JVM会为其创建方法调用栈和程序计数器,当然,处于这个状态中的线程并没有开始运行,只是表示已具备了运行的条件,随时可以被调度。至于什么时候被调度,取决于JVM里线程调度器的调度。

注意:
程序只能对新建状态的线程调用start(),并且只能调用一次,如果对非新建状态的线程,如已启动的线程或已死亡的线程调用start()都会报错IllegalThreadStateException异常。

3.运行

如果处于就绪状态的线程获得了CPU资源时,开始执行run()方法的线程体代码,则该线程处于运行状态。如果计算机只有一个CPU核心,在任何时刻只有一个线程处于运行状态,如果计算机有多个核心,将会有多个线程并行(Parallel)执行。

4.阻塞

当在运行过程中的线程遇到如下情况时,会让出CPU并临时中止自己的执行,进入阻塞状态:

  • 线程调用了sleep()方法,主动放弃所占用的CPU资源;
  • 线程试图获取一个同步监视器,但该同步监视器正被其他线程持有;
  • 线程执行过程中,同步监视器调用了wait(),让它等待某个通知(notify);
  • 线程执行过程中,同步监视器调用了wait(time);
  • 线程执行过程中,遇到了其他线程对象的加塞(join);
  • 线程被调用suspend方法被挂起(已过时,因为容易发生死锁);

当前正在执行的线程被阻塞后,其他线程就有机会执行了。针对如上情况,当发生如下情况时会解除阻塞,让该线程重新进入阻塞状态,等待线程调度器再次调度它:

  • 线程的sleep()时间到;
  • 线程成功获得了同步监视器;
  • 线程等到了通知(notify);
  • 线程wait的时间到了
  • 加塞的线程结束了;
  • 被挂起的线程又被调用了resume恢复方法(已过时,因为容易发生死锁);

5.死亡

线程会以以下三种方式之一结束,结束后的线程就处于死亡状态:

  • run()方法执行完成,线程正常结束
  • 线程执行过程中抛出了一个未捕获的异常(Exception)或错误(Error)
  • 直接调用该线程的stop()来结束该线程(已过时)

JDK1.5及之后:6种状态

在java.lang.Thread.State的枚举类中这样定义:

public enum State {NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
}

下图中在JAVA基础阶段暂时了解一下,不去看里面具体方法,以后在JUC里面再看

在这里插入图片描述


http://www.ppmy.cn/news/85441.html

相关文章

Java调用第三方库JNA(C/C++)

GitHub - java-native-access/jna: Java Native Access 源代码 在Java 中使用C语言库的传统做法是使用JNI编程。但是现在有更好的替代方案&#xff0c;即JNA(Java Native Access)&#xff1b;JNA是一个开源的Java框架,是SUN公司推出的调用本地库方法的技术&#xff0c;是建立在…

【计算机网络基础】辨析专题⑥ 应用层

文章目录 重要简写重要概念重要简写 域名系统——DNS文件传送协议——FTP简单文件传送协议——TFTP远程终端协议——TELNET万维网——WWW统一资源定位符——URL超文本传送协议——HTTP超文本标记语言——HTML可扩展标记语言——XML可扩展超文本标记语言——XHTML层叠样式表——…

图结构-图的数据表示法(java)

图结构 常见的图的数据表示法自定义一种数据结构来表示图。将一个线段集合转成我们自定义的图 常见的图的数据表示法 1.邻接矩阵表示法&#xff1a;用二维数组存储图的信息&#xff0c;数组中的对角线为0&#xff0c;表示不存在顶点到自身的边。若两个顶点之间有一条弧&#xf…

10款提效的在线设计工具推荐

在效率为王的时代&#xff0c;在线设计是设计的未来&#xff0c;为设计师提供了更节省时间、精力和成本的解决方案。 在线设计工具可以通过打开浏览器使用&#xff0c;大多数操作界面比传统设计工具更简单&#xff0c;入门门槛很低。 在这篇文章中&#xff0c;我们精心挑选了…

微信小程序的生命周期

微信小程序的生命周期 1.什么是生命周期&#xff1f;2.生命周期的分类3.什么是生命周期函数&#xff1f;4.生命周期函数的分类5.应用生命周期函数6.页面周期函数7.组件的生命周期函数lifetimes节点 8.组件所在页面的生命周期①什么是组件所在页面的生命周期&#xff1f;②pageL…

SeaTunnel本地运行以及kafka发送到redis说明

下载 Seatunnel2.3.1源码 Idea中的目录结构 编译 通过maven进行代码编译 编译命令 mvn clean package -pl seatunnel-dist -am -Dmaven.test.skiptrue 编译单个模块命令 mvn clean package -pl seatunnel-examples/seatunnel-engine-examples -am -Dmaven.test.skiptrue …

DJ8-3 shell 进程监控(ps、sleep、kill)

目录 8.6 进程监控 8.6.1 获取进程状态信息&#xff1a;ps 命令 8.6.2 暂停进程运行&#xff1a;sleep 命令 8.6.3 终止进程运行&#xff1a;kill 命令 8.6 进程监控 8.6.1 获取进程状态信息&#xff1a;ps 命令 1、不带参数的 ps 不带参数的 ps 命令运行时&#…

利用无代码工具开发一款小程序

目录 无代码工具开发小程序的流程需求分析阶段模型设计阶段页面搭建阶段创建项目创建数据表组件搭建 预览发布总结 日常我们开发小程序的时候都是要从写代码开始&#xff0c;但是写代码这个事只有专业开发才可以干&#xff0c;那作为普通人&#xff0c;如果也希望开发小程序&am…