Thread类的基本用法
创始人
2025-05-30 14:42:07
0

Thread

  • 小小的回顾
  • 初识线程
  • 创建线程
    • 继承Thread类
    • 构造方法中传入Runnable实例
    • 匿名内部类创建Thread子类
    • 匿名内部类实现Runnable接口实例
  • 线程休眠
  • 线程中断
  • 线程等待
  • 获取线程实例

小小的回顾

上一篇博客中,阿涛大概领着大家认识了一下进程.进程就是任务管理器中一个个打开的程序,比如我们现在打开了一个腾讯QQ,我们既需要用它来聊天,也需要用它来刷空间,显然这是两个不同的逻辑,我们需要通过不同的代码来实现这个逻辑.一个QQ是有好多好多的功能的,如果我们就按照代码的书写顺序来运行,那么极有可能同一时间能过实现的功能是极其有限的,此时此刻老祖宗留下的至理名言起到了关键作用:人多力量大!

初识线程

我们可以把进程想象成一个个工厂,那么线程就是工厂里面的一个个流水线,为了提高工厂的效率,我们就需要在条件允许的情况下设置流水线.我们现在的电脑都是多核心多线程的,核心越多线程越多,电脑并发编程的能力越强.
刚才说到的,进程也能做到线程能做到的事情,那么我们为什么不多搞几个线程呢?
其实线程本身不叫线程,线程的真名是"轻量级进程",只不过我们程序猿在学习工作的时候需要进行区分而已,"轻量级"主要体现在除了第一次创建线程我们需要有一定的开销,由于个个线程是共用一块地址空间的,所以之后的创建线程就有现成的地方了,同理,调用和销毁进程的开销是要大于调用和销毁线程的!
还是类比工厂和流水线,要建厂的开销一定比在厂里面增加一条流水线要来的大吧!!

创建线程

其实只要我们psvm了一下,我们就创建好了一个main线程,所以一般一个java程序一定至少会有一个线程.

继承Thread类

    static class MyThread extends Thread{@Override//继承Thread类并且需要重写里面的run方法,可以把run方法看成是Thread里面的main方法public void run(){System.out.println("hi,t");}}public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();//创建好MyThread实例只是做好了准备工作,此时程序里面并没有真正创建好一个线程//就好比跑步比赛的预备,各就各位//只有在这里调用了start()方法,线程才是真正地创建了出来System.out.println("hi,main");}

构造方法中传入Runnable实例

    static class MyRunnable implements Runnable {@Override//创建MyRunnable类实现Runnable接口,这里的重写人家是会强制你去做的public void run() {System.out.println("hi,t");}}public static void main(String[] args) {Runnable runnable = new MyRunnable();Thread t = new Thread(runnable);//在构造方法里面传入MyRunnable实例t.start();//还是需要调用start方法的System.out.println("hi,main");}

匿名内部类创建Thread子类

    public static void main(String[] args) {Thread t = new Thread(){//这种写法相当于是创建了一个一次性的Thread类的子类,并且重写其中的run方法//匿名内部类主要就是应用于一次性使用的场景下,没有类名但是能且只能使用这一次@Overridepublic void run(){System.out.println("hi,t");}};t.start();System.out.println("hi,main");}

匿名内部类实现Runnable接口实例

    public static void main(String[] args) {Thread t = new Thread(()->{System.out.println("hi,t"); });t.start();System.out.println("hi,main");}

这个基本上就是最简洁的版本了,以后也是使用的比较多的一个版本.

线程休眠

休眠就是睡觉,睡觉就是sleep,休眠模式下面的线程是没有办法申请CPU资源的,当我们不希望线程快速上CPU时就会搞这一套:

    public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{System.out.println("hi,t");});t.start();Thread.sleep(100);//sleep后面加上一个休眠的时间,到点了线程就会起床干事情System.out.println("hi,main");}

在这里插入图片描述
之前我们说过,一般来说t线程是要在main线程之后才跑起来的,但是此时我们加上了Thread.sleep() ,一切就不一样了,在我们看来100ms可能就是白驹过隙,我打字的功夫就不知道过去多少个100ms了,但是在计算机看来100ms就是沧海桑田,等待这一会的功夫已经跑了N行代码了,所以在main线程休眠的这段时间里面,y线程跑起来并执行了里面的run方法

线程中断

想要中断一个进程,就是要让进程里面的run方法跑完,就以循环为例子:

    public static boolean flag = false;//如果这里不是一个成员变量,好像是不可以在lambda表达式里面使用的,所以要设置一个成员变量public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while(!flag){System.out.println("hi,t");}System.out.println("线程结束");//如果循环结束了,跑到了这一行,只要打印完这一行那么线程也就结束了});t.start();Thread.sleep(100);//不加这个的话main线程执行的比t线程快,是不会有打印内容的flag = true;System.out.println("main结束");}

在这里插入图片描述
从结果上来看,确实达到了我们的预期效果,只不过这里我们是使用了外部变量来控制线程的,其实我们的Thread中是有内置的标志位的:

    public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while(!currentThread().isInterrupted()){System.out.println("hi,t");}System.out.println("t结束");});t.start();Thread.sleep(10);t.isInterrupted();System.out.println("main结束");}

在这里插入图片描述
当我们需要interrupt一个正在sleep或者其他阻塞状态下的线程是,就会通过抛出异常的方式唤醒线程,有没有一点你永远没办法叫醒一个装睡的人的意思呢?

线程等待

 	public static int num = 0;//main是一个静态方法,非静态的属性方法是没法在静态函数中使用的//lambda表达式中是不可以使用普通变量的,所以我们把这里的变量给调整成成员变量public static void main(String[] args) {Thread t = new Thread(()->{for (int i = 0; i < 5; i++) {num++;}});t.start();System.out.println(num);}

在这里插入图片描述按照我们的预设,应该是在t线程里面完成了自增操作啊,为什么最后我们显示出来的还是0嘞?
我们之前应该说过,因为创建线程是需要一定的系统开销的,所以main线程一般情况是是要比其他线程提前执行的,所以我们在sout的时候,num还是0.要是想要达到我们的预期,就需要让main线程等待t线程执行完,这时候,就涉及到了线程的等待,这里我们先讲解一个join()方法,后期我们再讲解别的方法:

在这里插入图片描述
那么我们在main线程中调用了一个t.join()这就是让main线程等待t线程执行完然后再执行,这下子我们就得到了自己想要的.

获取线程实例

    public static void main(String[] args) {Thread t = new Thread(()->{System.out.println(Thread.currentThread());});t.start();System.out.println(Thread.currentThread());}

我们可以直接通过currentThread()这个静态方法来获取到当前线程的实例,在t线程中拿到的就是t线程,在main线程中拿到的就是main线程的实例:
在这里插入图片描述
看样子Thread类是重写了toString()方法,同时我们可以看到实例方法还是有不少的,在学习的过程中可以随时使用.
好了,那么今天关于线程的学习就到这里了,希望我的这篇博客可以帮助到大家.
百年大道,你我共勉!

相关内容

热门资讯

生成式AI为百度打开想象力 出品 | 何玺 排版 | 叶媛 3月16日,备受期待的百度人工智能系统文心一言正式发布...
javaweb实验室学生考勤签... 管理员信息表,包括自动编号,管理员账号,登录密码等数据字段...
提供一种嵌套表单的校验姿势 文章目录一、表单校验1. 代码演示 一、表单校验 表单校验,前端经常遇到的校验场景&...
go语言入门-一文带你掌握go... 前言 本文go语言入门-掌握go语言函数收录于《go语言学习专栏》专栏,此专栏带你从零...
【Vue3】tinymce富文... 1.简介 TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有:...
量子计算(10)量子算法2:D...         又到了一周一篇的量子计算啦!全体起立respect! ...
十六、FreeRTOS中如何实... 文章目录1、多任务系统中为什么要引入互斥?2、如何实现互斥访问的3、需要互斥访问内核对...
如何把自有数据接入GPT大模型... ChatGPT引发了AI革命,大家都想探究如何让它发挥更大价值。 以它为代表的大模型并...
美国中重卡销量10强:福莱纳领... 陌生的美国中重卡市场在我们的一般印象中,全球各国的汽车市场互联互通,应该是大同小异的。无论是是美国、...
Android WebView... 1、不使用WebView缓存 使用场景:通过WebView输入用户名和密码进行登录&#...
阿里云PAI-DeepRec ... 阿里云联合英特尔举办的“创新大师杯”全球AI极客挑战赛——PAI-DeepRec CTR模型性能优化...
拒绝转保!34年编外员工办不了... 临近退休了,突然被强制“自愿转保”,河北井陉县税务局的冯爱文拒绝签字,导致办理不了退休,到底发生了什...
中原证券:A股6月有望延续结构... 展望A股6月行情,中原证券在最新研报中表示,总体而言,6月A股在政策托底与盈利修复的共振下,有望延续...
【C++】类和对象三大特性--... 文章目录1. 多态的基本概念2. 多态的定义及实现2.1多态的构成条件2.2 虚函数2.3虚函数的重...
潜在因子模型(Latent F... LatentFactorModelsLatent Factor ModelsLatentFactor...
Java Web 实战 15 ... 文章目录一 . 网络编程中的基本概念1.1 网络编程1.2 客户端(client) / 服务器(se...
谁是车圈恒大,魏建军发对脾气了... “整体来看,中国主流车企的资产负债情况要好于国外车企,中国主流车企根本不存在所谓的‘车圈恒大’。”继...
项目二 任务三 训练3 交换机... 按图所示设置PC的IP地址,交换机主机名。 1、交换机的基本配置 (1...
九九乘法表-第14届蓝桥杯ST...  [导读]:超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成࿰...
端午粽市火热,辣条粽、养生粽等... 红星资本局5月31日消息,今日正值端午假期,红星资本局走访线下商超发现,今年多个品牌推出新品,不少商...