初识Thread类与创建多线程的方法

news2024/11/24 3:37:00

目录

1.创建一个线程

2.start()方法与run()方法

3.查看线程

4.创建线程的各种方法

4.1实现Runnable接口

4.2使用匿名内部类

4.3使用匿名内部类,实现Runnable

4.4使用Lambda表达式


1.创建一个线程

Java操作线程最核心的类就是Thread类

创建线程有很多方法,下面我们写一个Mythread类继承 Thread 类重写run()方法来创建线程

package thread;
class MyThread extends Thread{
    public void run(){
        System.out.println("hello world!");
    }

}
public class ThreaDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
    }
}

这里的Thread类不需要import包,是因为这个类和String,StringBuffer这些类一样是在java.lang包中,已经自动导入了!

run()方法是重写了Thread类的run()方法,重写就是和父类方法名参数都相同,子类的方法通过动态绑定机制被调用

就像上面的:

Thread t = new MyThread();
t.run();

这里的t是父类的引用,调用的 run()仍然是子类的方法,本质上t还是指向子类对象

重载是同一个作用域,多个方法的方法名相同,参数个数或类型不同的方法

2.start()方法与run()方法

我们用t调用一个strat方法

public class ThreaDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
    }
}

这里的hello world和我们直接在打印出来的hello world是不同的!!!

这里的是由 t.start()创建了一个新的线程,然后由线程负责执行t.run(),打印出hello world!

  t.start()创建新的线程时,调用了操作系统的API,通过操作系统内核创建新线程的PCB,并把要执行的指令交给这个PCB,当PCB被调度到CPU上执行的时候,就能执行到run()方法中的代码了

直接打印hello world时,java进程就只有一个线程(就是调用main方法的线程)也就是主线程

通过 t.start(),主线程调用了t.start(),t.start()创建出新的线程,新的线程调用t.run();

当run()方法执行完毕,新的的线程就自动销毁

创建线程归结到底还是要解决并发编程问题,我们来看一个并发的例子

class MyThread extends Thread{
    public void run(){
        while(true){
            System.out.println("hello world!");
            //休眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

}
public class ThreaDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();

        while(true){
            System.out.println("hello main!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

这段代码并不是只执行到一个循环,死循环出不来了,而是交替执行的

 这就是并发执行的效果,执行的顺序也是不确定的,主要原因是:操作系统调度线程的时候是"抢占式执行",具体哪个线程先执行,哪个线程后执行,都是不确定的,取决于操作系统调度策略

虽然也是有优先级的,但是从应用程序方面来看到的效果是随机的,我们在程序上无法修改的

如果我们只执行t.run()会是什么情况呢?

 结果

这里只执行了run方法,没有执行hellomain这里,是因为只有一个主线程是单线程工作的

不会交替执行,这就是单线程和多线程的差异

run()和start()的区别

run是线程里的方法,描述的是线程要执行的任务,但是线程还没有执行,只有调用start后,线程才会开始运行,调用后会申请线程并执行run方法,执行完后进入销毁线程阶段,也就是说strat才是真正创建了线程,并且线程是独立的执行流

3.查看线程

我们可以使用jdk自带的工具jconsole查看当前的java进程中的所有线程

这个工具一般路径:C:\Program Files\Java\jdk1.8.0_192\bin

双击打开运行会看到本地进程

接下来点击一下我们运行的程序的线程

 

点击线程

 可以看到有很多线程

详细信息 

 其它的线程都是JVM自带的线程

注意:如果打开工具本地进程什么也没有,可以尝试用右键,管理员方式运行

 new Thread 对象时,不创建线程,调用start才是创建PCB才有真实的线程

主线程调用就是start方法写到main方法中被调用

4.创建线程的各种方法

Java中创建线程的方法有很多种,上面使用的就是继承Thread类,重写run()方法的方法,下面了解一下其他三种方法

4.1实现Runnable接口

回顾:

抽象类和普通类的区别:抽象类不能实例化,不能直接new,必须有子类继承抽象类,然后抽象类中有抽象方法,抽象方法没有方法体,需要子类重写抽象方法

接口比抽象类更进一步,抽象类除抽象方法之外还有普通方法和属性,接口则是只有抽象方法

class MyRunnable implements Runnable{
    public void run(){
        System.out.println("hello thread!");
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        Thread t = new Thread(runnable);
        t.start();
    }
}

Runnable是描述任务,具体执行细节就是run()方法,任务还要交给线程来执行

使用Runnable接口达到了解耦合的目的,将线程和线程的任务分开,如果要修改代码,代码改动就比较小

4.2使用匿名内部类

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("hello world!");
            }
        };
                t.start();
    }
}

这里创建了一个Thread的子类,子类是匿名的,还创建了子类的实例,并且让t指向实例 

4.3使用匿名内部类,实现Runnable

public class ThreadDemo4 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world!!");
            }
        });
        t.start();
    }
}

写法和1本质相同,只不过把实现Runnable 任务交给匿名内部类的语法,此处是创建了一个类,实现Runnable,同时创建了实例 ,并且把实例传给Thread的构造方法(匿名内部类的创建的实例作为Thread的构造方法参数)

4.4使用Lambda表达式

这是比较简单的,推荐的写法

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("hello world!!");
        });
        t.start();
    }
}

把任务通过Lambda表达式来描述,直接把Lambda表达式传给Thread的构造方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/53637.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]计算机毕业设计springboot人体健康管理app

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

SpringBoot结合XXL-JOB实现定时任务

《从零打造项目》系列文章 工具 比MyBatis Generator更强大的代码生成器 ORM框架选型 SpringBoot项目基础设施搭建SpringBoot集成Mybatis项目实操SpringBoot集成MybatisPlus项目实操SpringBoot集成Spring Data JPA项目实操 数据库变更管理 数据库变更管理:Liquibase…

阿里自爆秋招面试笔记,福音来了

前言 最近又掀起了一股面试招聘风潮,我们一边要巩固基础知识、备战试题的同时,另外与面试官的对达沟通也直接影响你的成功与否!那我们应该如何做好准备呢? ​先说面试过程,今天阿鑫给大家整理了这三个小经验&#xf…

笔试强训Day2

选择题 1. 思路:e是按指数类型输出,f是按照浮点数类型输出(输出只有f不用lf) 输出默认是右对齐,-则是左对齐,四位精度就是小数点后保留几位用.4,输出字符数用整数30在小数点前表示即可。 如果…

MySQL数据库复习——索引

目录 一、什么是索引?索引的作用 二、索引的简单使用 三、索引背后的数据结构 1、B 树 2、B 树 一、什么是索引?索引的作用 索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引,并指…

Nacos 配置中心

1. 什么是配置中心 1.1 什么是配置 应用程序在启动和运行的时候往往需要读取一些配置信息,配置基本上伴随着应用程序的整个生命周期,比如:数据库连接参数、启动参数等。 配置主要有以下几个特点: 配置是独立于程序的只读变…

java基础讲义03

java基础讲义一 流程控制1.1流程控制语句介绍1.2顺序结构二 选择控制2.1 选择结构介绍2.2 选择语句if2.2.1 格式12.2.2 if格式22.2.3 if格式32.3 选择语句switch2.3.1 switch语句介绍2.3.2 switch注意事项2.3.3 switch面试题2.3.4 if语句与switch语句区别三 循环语句3.1 循环语…

Yolov5 计算访存量MAC与计算量FLOPS

说明:因为yolov5函数中已经计算了 FLOPS,因此如果想要计算访存量那么只需按照flops的位置,添加访存量的计算即可 一、先记住计算量和访存量的公式: 二、找到计算FLOPS的位置,并添加访存量 yolov5中计算flops的位置在torch_utile…

微服务外交官-Feign

引言 书接上篇 负载均衡组件Ribbon核心-LoadBalanced-下 我们讲完了Ribbon负载均衡原理之后,接下讲一个SpringCloud Alibaba新的组件:Fegin 前面章节我们使用Ribbon方式实现负载均衡版的远程调用, //方案4:使用Ribbon方式--带负…

不知道10年老电脑如何重装系统?其实很简单

肯定很多朋友家里都有一两台吃灰的10年老电脑了,当我们有空可以把它拿出来耍耍的时候,却发现电脑无法开机了,想拿去修又觉得不太值得。其实我们可以先试着给电脑重装系统,这样也能先排查系统是否有问题。如果你不知道这台10年老电…

【Linux】Linux编译器-gcc/g++使用

大家好我是沐曦希💕 文章目录1.背景知识1.1 预处理1.2 编译(生成汇编)1.3 汇编(生成机器可识别代码)1.4 链接接(生成可执行文件或库文件)1.5 习题习题一习题二2.函数库2.1 动态库2.2 静态库3.g的基本使用4.…

数据结构之二叉树

数据结构之二叉树什么是二叉树二叉树的特殊类型二叉树的遍历方式二叉树的叶子结点求法二叉树的高度求法什么是二叉树 二叉树(Binary tree)是树形结构的一个重要数据类型,想要成为二叉树必须满足两个条件。1、本身是有序树。2、树中包含的各个…

【小程序】导航栏和内容页面联动效果实现

💭💭 ✨: 微信小程序导航栏和页面联动   💟:东非不开森的主页   💜: 因为很多东西来不及去做去看可是时间很快总是赶不上,所以要去成长呀💜💜   🌸: 如有错…

React—— HelloWorld

React 学习笔记Hello WorldJSX (JavaScript XML) 语法规则JavaScript 语法函数组件、类组件 & 属性 props组合组件生命周期函数 & 状态 state事件处理refs受控组件、非受控组件 & 高阶函数、函数的柯里化npm参考Hello World <!DOCTYPE html> <html lang&…

Request请求转发与Respones请求重定向有什么区别?

目录&#xff1a; 1.Request请求转发 2.Respones请求重定向 3.关于转发和重定向的路径问题 1.Request请求转发 请求转发(forward)是一种在服务器内部的资源跳转方式。 (1)浏览器发送请求给服务器&#xff0c;服务器中对应的资源A接收到请求 (2)资源A处理完请求后将请求发…

在html中使用js实现图片的无缝滚动(四种状态)

文章目录js原理实施任务1.从左往右无缝滚动代码示例运行效果2.从右往左无缝滚动代码示例运行效果3.从上往下无缝滚动代码示例运行效果4.从下往上无缝滚动代码示例运行效果js原理 获取整个ul和ul下面的所有li&#xff0c; 把ul里面的li内容添加一份&#xff0c;因为需要完成图片…

【加油站会员管理小程序】01需求分析

随着这两年微搭产品的迭代,目前组件基本够用,像常用的支付这种功能也是有的,因此我们就可以结合现有功能来完成一个实际使用的小程序的开发。 我们本次的实战课,是以加油站的业务场景为出发点,涵盖会员的开通、充值、消费、积分兑换等常用场景。结合实战案例,我们完整的…

12月2日:thinkphp中的链式操作

补充内容&#xff1a; 今天我们就来聊聊limit和page的区别以及group by需要注意的点&#xff0c;where和having的区别 limit和page 区别 Limit 限制查询数量&#xff0c;在进行分页查询的时候用的最多&#xff0c;但是limit在查询限制中的索引值是从0开始的&#xff0c;lim…

基于Java+Springboot+Vue+elememt疫情返乡人员管控系统设计实现

博主介绍&#xff1a;✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取联系&#x1f345;精彩专栏推荐订阅收藏&#x1f447;&…

一文搞懂如何学习Android内部命令行工具集合

目录 1.安卓命令工具集 2.命令如何使用&#xff08;举例&#xff09; 2.1 am命令使用 2.2 dumpsys 命令使用 2.3 wm命令用法 2.4 rm命令的用法 2.5 logcat 命令的用法 2.6 cat 命令的用法 3.个人如何学习 3.1 推荐学习方法一 3.2 方法二 1.安卓命令工具集 安卓支持…