Java-宋红康-(P133-P134)-多线程创建方式(Thread and Runnable)

b站视频

133-多线程-线程创建方式1:继承Thread类_哔哩哔哩_bilibili

目录

3.1 继承Thread

3.1.1 继承Thread类方式

3.1.2 线程的执行流程

3.1.3 线程内存图

3.1.4 run()方法和start()方法

3.1.5 线程名字的设置和获取

3.1.6 获取运行main方法线程的名字

3.1.7 练习题

3.2 实现 Runable

3.2.1 实现Runnable接口方式

3.2.2 Thread和Runnable的对比

3.2.3 匿名内部类方式创建线程


3.1 继承Thread

3.1.1 继承Thread类方式

Java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。Java中通过继承Thread类来创建启动多线程的步骤如下:

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。

  2. 创建Thread子类的实例,即创建了线程对象

  3. 调用线程对象的start()方法来启动该线程

自定义线程类:

class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("自定义线程正在执行!"+i);
        }
    }
}

测试类:

public class Main {
    public static void main(String[] args)  throws Exception{
        MyThread mt=new MyThread();
        mt.start();
        for (int i = 0; i < 20; i++) {
            System.out.println("main线程"+i);
        }
    }
}

结果:

3.1.2 线程的执行流程

程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用mt的对象的start方法,另外一个新的线程也启动了,这样,整个应用就在多线程下运行。

通过这张图我们可以很清晰的看到多线程的执行流程,那么为什么可以完成并发执行呢?我们再来讲一讲原理。

多线程执行时,到底在内存中是如何运行的呢?以上个程序为例,进行图解说明:

多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。

3.1.3 线程内存图

当执行线程的任务结束了,线程自动在栈内存中释放了。但是当所有的执行线程都结束了,那么进程就结束了。

3.1.4 run()方法和start()方法

  • run()方法,是线程执行的任务方法,每个线程都会调用run()方法执行,我们将线程要执行的任务代码都写在run()方法中就可以被线程调用执行。

  • start()方法,开启线程,线程调用run()方法。start()方法源代码中会调用本地方法start0()来启动线程:private native void start0(),本地方法都是和操作系统交互的,因此可以看出每次开启一个线程的线程都会和操作系统进行交互。

注意:一个线程只能被启动一次!!

实例:

package test;

public class TestDemo03 {
    public static void main(String[] args) {
        //创建当前Thread的子类的对象
        PrintNumber t1=new PrintNumber();
        //通过对象调用start()
        t1.start();

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}


class PrintNumber extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

结果:

问题1:能否用t1.run()方法替换t1.start()的调用,实现分线程的创建和调用。

package test;

public class TestDemo03 {
    public static void main(String[] args) {
        //创建当前Thread的子类的对象
        PrintNumber t1=new PrintNumber();
        //通过对象调用start()
       // t1.start();
        t1.run();
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}


class PrintNumber extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

结果:(输出的全是main,通过调用run方法后变成了单线程)

3.1.5 线程名字的设置和获取

  • Thread类的方法String getName()可以获取到线程的名字。

  • Thread类的方法setName(String name)设置线程的名字。

  • 通过Thread类的构造方法Thread(String name)也可以设置线程的名字。

public class MyThread  extends Thread{
    public void run(){
        System.out.println("线程名字:"+super.getName());
    }
}

测试类:

public class Demo {
    public static void main(String[] args) {
        //创建自定义线程对象
        MyThread mt = new MyThread();
        //设置线程名字
        mt.setName("旺财");
        //开启新线程
        mt.start();
    }
}

注意:线程是有默认名字的,如果我们不设置线程的名字,JVM会赋予线程默认名字Thread-0,Thread-1。

3.1.6 获取运行main方法线程的名字

  • Demo类不是Thread的子类,因此不能使用getName()方法获取。

  • Thread类定义了静态方法static Thread currentThread()获取到当前正在执行的线程对象。

  • main方法也是被线程调用了,也是具有线程名字的。

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

结果:

3.1.7 练习题

创建两个分线程,其中一个线程遍历100以内的偶数,另一个线程遍历100以内的奇数。

package test;

public class TestDemo03 {
    public static void main(String[] args) {
        //创建当前Thread的子类的对象
        PrintNumber t1=new PrintNumber();
        //创建当前Thread的子类的对象
        PrintOddNumber t2=new PrintOddNumber();
        //通过对象调用start()
       t1.start();

        //通过对象调用start()
        t2.start();

    }
}

//遍历100以内的偶数
class PrintNumber extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i%2==0) {
                System.out.println(Thread.currentThread().getName() +"--" + i);
            }
        }
    }
}

//遍历100以内的奇数
class PrintOddNumber extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i%2==1) {
                System.out.println(Thread.currentThread().getName() +"--"+i);
            }
        }
    }
}

结果:

3.2 实现 Runable

3.2.1 实现Runnable接口方式

采用java.lang.Runnable也是非常常见的一种,我们只需要重写run方法即可。

步骤如下:

  1. 创建一个实现Runnable接口的类

  2. 实现接口中的run()方法 --> 将此线程要执行的操作,声明在此方法体中

  3. 创建Runnable实现类的实例

  4. 将此对象实例作为参数传递到Thread类的构造器中,创建Thread类的实例

  5. Thread类的实例调用start()方法:①启动线程 ②调用当前线程的run()。

package test;

public class TestDemo04 {
    public static void main(String[] args) {
        //③ 创建当前实现类的对象
        EvenNumberPrint evenNumberPrint=new EvenNumberPrint();
        //④ 将此对象作为参数传递到Thread类的构造器中,创建Thread类的实例
        Thread t1=new Thread(evenNumberPrint);
        //⑤ Thread类的实例调用start():1.启动线程 2. 调用当前线程的run()方法
        t1.start();
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"---"+i);
        }
    }
}

//① 创建一个实现Runnable接口的类
class EvenNumberPrint implements Runnable{
    //② 实现接口中的run() -->将此线程要执行的操作,声明在此方法中。
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"---"+i);
        }
    }
}

结果:

通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个执行目标。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。

在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread对象的start()方法来运行多线程代码。

实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是继承Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的,熟悉Thread类的API是进行多线程编程的基础。

3.2.2 Thread和Runnable的对比

共同点:

  • 启动线程,使用的都是Thread类中定义的start()方法

  • 创建的线程对象,都是Thread类或其子类的实例。

不同点:

一个是类的继承,一个是接口的实现。

建议:建议使用实现Runnable接口的方式

Runnable方式的好处:

①实现的方式,可以避免类的单继承的局限性。

②更适合多个相同的程序代码的线程去共享同一个资源。

③增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

联系: public class Thread implements Runnable(代理模式)

3.2.3 匿名内部类方式创建线程

使用线程的内匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作。

使用匿名内部类的方式实现Runnable接口,重新Runnable接口中的run方法:

public class NoNameInnerClassThread {
           public static void main(String[] args) {                   
//                new Runnable(){
//                        public void run(){
//                                for (int i = 0; i < 20; i++) {
//                                        System.out.println("张宇:"+i);
//                                }
//                        }  
//                   }; //---这个整体  相当于new MyRunnable()
        Runnable r = new Runnable(){
            public void run(){
                for (int i = 0; i < 20; i++) {
                          System.out.println("张宇:"+i);
                }
            }  
        };
        new Thread(r).start();

        for (int i = 0; i < 20; i++) {
                  System.out.println("费玉清:"+i);
        }
           }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java Web学习笔记】5 - XML

项目代码 https://github.com/yinhai1114/JavaWeb_LearningCode/tree/main/xml 零、在线文档 XML系列教程 一、XML引出 1.为什么需要XML 1.需求1 :两个程序间进行数据通信? 2.需求2:给一台服务器&#xff0c;做-一个配置文件&#xff0c;当服务器程序启动时&#xff0c;去…

【AntDB 数据库】国产数据库发展之信创政策的加持

由于我国在信息技术领域起步较晚&#xff0c;国内大量的市场份额被国际IT巨头占据&#xff0c;甚至长期处于被垄断的地位&#xff0c;这也给了某些国家妄图通过挑起科技、贸易摩擦制衡我国发展的机会。为了解决可能存在的安全风险&#xff0c;在重要信息系统、关键基础设施中使…

linux-进程退出

进程终止 进程终止进程终止原因 进程返回值echo $?exit()和_exit() 父进程获取进程退出码wait()方法waitpid()方法获取子进程的退出码&#xff08;status&#xff09; 进程的非阻塞等待(WNOHANG)问题 进程终止 进程终止原因 进程终止原因有三种情况。 代码运行完毕&#xf…

【多线程】-- 12 线程协作之生产者消费者问题及解决办法

多线程 9 线程协作 “生产者消费者问题” ——并非二十三种设计模式之一 9.1 生产者消费者问题 “线程通信” 应用场景&#xff1a;生产者和消费者问题 假设仓库中只能存放一件产品&#xff0c;生产者将生产出来的产品放入仓库&#xff0c;消费者将仓库中产品取走消费如果…

linux 服务的JDK安装

1.jdk安装 1.1 jdk下载 官网下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/ 这里我使用的是rpm的方式&#xff0c;所以下载rpm的包。如下图&#xff1a;1.2 jdk的安装 下载完成后&#xff0c;会有一个以rpm结尾的包&#xff0c;例如&#xff1a;jd…

【恋上数据结构】哈夫曼树学习笔记

哈夫曼树 哈夫曼编码&#xff08;Huffman Coding&#xff09; 哈夫曼编码&#xff0c;又称为霍夫曼编码&#xff0c;它是现代压缩算法的基础 假设要把字符串 [ABBBCCCCCCCCDDDDDDEE] 转成二进制编码进行传输。 可以转成 ASCII 编码 (6569&#xff0c;10000011000101) &…

牛客算法题【HJ96 表示数字】golang实现

题目 HJ96 表示数字 golang实现 package mainimport ("fmt""unicode" )func main() {s : ""var s_o stringvar char_pre, r runefor {n, _ : fmt.Scan(&s)if n 0 {break} else {for _, r range s {if unicode.IsDigit(r) {if !unicode.…

前端模拟新闻列表ajax请求 mocky

效果图&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title> </head><style>ul {display: flex;flex-wrap: wrap;justify-content: space-between;}ul::after{content: ;width: 30%;}a…

L1-004:计算摄氏温度

题目描述 给定一个华氏温度F&#xff0c;本题要求编写程序&#xff0c;计算对应的摄氏温度C。计算公式&#xff1a;C5(F−32)/9。题目保证输入与输出均在整型范围内。 输入格式&#xff1a;输入在一行中给出一个华氏温度。 输出格式&#xff1a;在一行中按照格式“Celsius C”…

创建vue3数学符号选择器(vue3+elementPlus+ts)

本文包含两种效果&#xff1a; 效果一&#xff1a;数学符号只能选择一次&#xff0c;选中的数学符号高亮 效果二&#xff1a;相同的数学符号可以选择多次&#xff0c;当前选中的数学符号高亮 首先创建math.ts定义常见数学符号数组 : export const symbols [{ id: 1, value: …

数据结构与算法-D2D3线性表之顺序表

线性表&#xff1a;包含若干数据元素的一个线性序列&#xff0c;特征如下&#xff1a; 1&#xff09;对非空表&#xff0c;a0是表头&#xff0c;无前驱&#xff1b; 2&#xff09;an-1是表尾&#xff0c;无后继&#xff1b; 3&#xff09;其他元素仅且仅有一个前驱&#xff0c;…

CSS面经(未完待续)

1. CSS选择器及其优先级 !important > 行内样式 > id选择器 > 类/伪类/属性选择器 > 标签/伪元素选择器 > 子/后台选择器 > *通配符 2. 重排和重绘是什么&#xff1f;浏览器的渲染机制是什么&#xff1f; 重排(回流)&#xff1a;当增加或删除dom节点&…

Centos7上安装Redis

第一步&#xff1a;安装Redis依赖 yum install -y gcc tcl //需要使用管理员权限第二步&#xff1a;下载上传安装包并解压 下载地址redis中文官网 上传成功后解压 输入tar -zxvf &#xff08;redis版本&#xff09;,即可解压成功 进入redis目录&#xff0c;运行编译命令&am…

人工智能学习3(特征变换:特征数值化)

编译工具&#xff1a;PyCharm 有些编译工具不用写print可以直接将数据打印出来&#xff0c;pycharm需要写print才会打印出来。 文章目录 编译工具&#xff1a;PyCharm 概念1.特征类型分类型二值型顺序型数值型 2.特征数值化练习13.特征数值化练习24.特征二值化使用sklearn库自…

信号是怎么搞到电磁波上面去的呢?

在之前的文章中&#xff0c;我们曾多次讲到电磁波的美妙&#xff0c;但是有了电磁波就可以通信了吗&#xff1f; No&#xff0c;我们要把信息加载到电磁波上&#xff0c;这个电磁波就可以作为信息的载体来工作了。可是信号是怎么加载到电磁波上的呢&#xff1f; 今天我们一起…

Javafx实现浏览器

浏览器是一种计算机程序&#xff0c;主要用于显示互联网上的网页。通过浏览器&#xff0c;用户可以访问各种网站、搜索引擎、在线应用程序、社交媒体等。常见的浏览器包括Google Chrome、Mozilla Firefox、Safari、Microsoft Edge、Opera等。浏览器的功能不仅限于浏览网页&…

无线网卡填坑记

没想到我安装无线网卡这么波澜起伏~ 起因 近来刚在电脑上玩完了 Dishonored 2&#xff0c;紧接着继续着我的刺客信条之旅。总是觉得键盘鼠标玩起来不爽&#xff0c;还是手柄玩这种游戏才舒服。突然&#xff0c;灵光一现&#xff0c;我想到正好有闲置的 Switch 掌机没怎么玩&am…

【代码随想录】算法训练计划39

dp 1、62. 不同路径 题目&#xff1a; 求路径方案多少个 思路&#xff1a; 这道题就有点dp了哈 func uniquePaths(m int, n int) int {//dp&#xff0c;写过,代表的是多少种// 初始化dp : make([][]int, m)for i : range dp {dp[i] make([]int, n)dp[i][0] 1 // 代表到…

【数据结构】图<简单认识图>

对于下面的内容&#xff0c;大家着重观察和理解图即可&#xff0c;可以直接绕过一些文字性的概念&#xff0c;对图有一个大概的认识。 图 简单认识图图的定义有向图和无向图完全图无向完全图有向完全图 图的基本存储结构邻接矩阵存储邻接矩阵的优点 网络的邻接矩阵邻接表无向图…

看懂lscpu的输出

文章目录 1. lscpu1.1 Architecture1.2 逻辑核心数1.3 缓存1.4 CPU型号1.5 NUMA架构1.5.1 CPU多核架构1.5.2 多CPU Socket架构 2. cat /proc/cpuinfo2.1 关键字段 1. lscpu 通过lscpu查看当前系统的CPU信息。 [hadoopserver3 ~]$ lscpuArchitecture: x86_64 …