学习多线程,创建多线程的三种方式

2023-11-15

多线程

并发与并行

并发:两个或多个事件在同一个时间段内发生(交替执行)。请添加图片描述
并行:两个或多个事件在同一个时刻发生(同时执行)。

进程与线程

进程:进入到内存中的程序。

在这里插入图片描述
线程:进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
在这里插入图片描述

线程调度

分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。

抢占式调度:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

用户可在任务管理器中的详细信息列表设置线程的优先级

主线程

主线程:执行main方法的线程,程序的执行从main方法开始,从上到下逐行执行

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println(name+"run"+i);
        }
    }
}
public class Demo01 {
    public static void main(String[] args) {
        Person p1 = new Person("aaa");
        p1.run();

        Person p2 = new Person("bbb");
        p2.run();
    }
}

java程序进入到内存中,JVM会先执行main方法,JVM会通过操作系统,开辟一条main方法通向cpu的路径,cpu通过这条路径执行main方法。这条路径的名字就叫主线程(main线程)。

创建多线程程序

创建多线程程序的第一种方式:继承thread类
java.lang.Thread:就是一个描述线程的类,类想实现多线程,就必须继承Thread类。
线程是程序中执行的线程。 Java虚拟机允许应用程序同时运行多个执行线程。

java程序属于抢占式调度:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个线程执行(线程随机性)

实现步骤

创建Thread类的子类,继承Thread类
在Thread类的子类中,重写Thread类的run方法,设置线程任务(开启新的线程的目的)
创建Thread类的子类对象
调用Thread类中的start方法开启新线程,执行线程任务run方法
void start(): 导致此线程开始执行, Java虚拟机调用此线程的run方法。结果是两个线程同时运行:当前线程(主线程:执行main方法中的代码)和另一个线程(新的线程:执行其run方法中的方法)。不止一次启动线程永远不合法。 特别是,一旦完成执行,线程可能无法重新启动。—>start方法只能执行一次

示例:通过继承thread类,创建多线程程序

//1.创建Thread类的子类,继承Thread类
public class MyThread extends Thread{
    //2.在Thread类的子类中,重写Thread类的run方法,设置线程任务(开启新的线程的目的)

    @Override
    public void run() {
        //新线程执行run方法
        for (int i = 0; i < 20; i++) {
            System.out.println("run-->"+i);
        }
    }
}
public class Demo01Thread {
    public static void main(String[] args) {
        //3.创建Thread类的子类对象
        MyThread mt = new MyThread();
        //mt.run(); 不会开启新线程
        mt.start();
        //main线程会继续执行for循环
        for (int i = 0; i < 20; i++) {
            System.out.println("main-->"+i);
        }

    }
}

新的线程和main线程优先级相同,cpu会随机执行某一个线程,就会出现随机性打印结果

run-->0
main-->0
main-->1
run-->1
main-->2
run-->2
main-->3
run-->3
main-->4
run-->4
run-->5
run-->6
run-->7
run-->8
run-->9
main-->5
run-->10
main-->6
run-->11
main-->7
run-->12
main-->8
run-->13
main-->9
run-->14
main-->10
run-->15
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
run-->16
main-->18
run-->17
run-->18
run-->19
main-->19

随机性打印结果原理:
1:JVM首先运行main方法,找到操作系统开辟一条通向cpu的路径,这个路径就是主线程,cpu通过这个路径就可以执行main
2:执行MyThread mt = new MyThread();,开辟一条新的通向cpu的路径。mt.start();用来执行run方法
3:现在有两条路径通向cpu,对于cpu而言就有了选择的权力,可以随机选择一个来执行(主线程和新线程的优先级相同),所以就有了随机性打印结果。
4:内存图解
在这里插入图片描述
获取线程的名称

主线程:main
新线程:Thread-0,Thread-1…Thread-n

使用Thread类中的getName方法
String getName() 返回此线程的名称。

public class MyThread extends Thread{
    @Override
    public void run() {
        //1.使用Thread类中的getName方法
        String name = getName();
        System.out.println(name);
  }
}
public class Demo01Thread {
    public static void main(String[] args) {
        //线程1
        MyThread myThread = new MyThread();
        myThread.start();//Thread-0
        //线程2
        new MyThread().start();//Thread-1
    }
}

可以先获取当前正在执行的线程,再通过getName获取线程名称
static Thread currentThread() 返回对当前正在执行的线程对象的引用。

public class MyThread extends Thread{
    @Override
    public void run() {
       //2.可以先获取当前正在执行的线程,再通过getName获取线程名称
        Thread currentThread = Thread.currentThread();
        String name = currentThread.getName();
        System.out.println(name);
    }
}
public class Demo01Thread {
    public static void main(String[] args) {
        //线程1
        MyThread myThread = new MyThread();
        myThread.start();//Thread-0
        //线程2
        new MyThread().start();//Thread-1

        //获取主线程名称
        System.out.println(Thread.currentThread().getName());
    }
}

设置线程的名称

可以使用Thread的方法setName
void setName​(String name) 将此线程的名称更改为等于参数 name 。

public class MyThread extends Thread{
 @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Demo01 {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.setName("aaa");
        mt.start();
    }
}

添加一个带参构造方法,参数传递线程的名称,调用父类的带参构造,把名字传递给父类

public class MyThread extends Thread{
    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Demo01 {
    public static void main(String[] args) {
        MyThread mt2 = new MyThread("bbb");
        mt2.start();//bbb
    }
}

Thread类中的sleep方法
static void sleep​(long millis) 导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。
示例:制作秒表

public class Demo01 {
    public static void main(String[] args) {
        //秒表
        for (int i = 0; i < 60; i++) {
            System.out.println(i);
            //让程序睡眠1s 1s=1000ms
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

创建多线程程序的第二种方式:实现Runnable接口
java.lang.Runnable
Runnable接口应由任何其实例由线程执行的类实现。 该类必须定义一个名为run的无参数的方法。

java.lang.Thread类的构造方法:

Thread​(Runnable target) 分配新的 Thread对象。
Thread​(Runnable target, String name) 分配新的 Thread对象。
实现步骤

1:创建一个类实现Runnable接口
2:重写Runnable接口中的run方法,设置线程任务
3:创建Runnable接口的实现类对象
4:创建Thread类对象,构造方法中传递Runnable接口的实现类对象
5:调用Thread类中的start方法,开启新线程,执行run方法

//1.创建一个类实现Runnable接口
public class RunnableImpl implements Runnable {
    //2.重写Runnable接口中的run方法,设置线程任务
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
public class Demo01 {
    public static void main(String[] args) {
        //3.创建Runnable接口的实现类对象
        RunnableImpl r = new RunnableImpl();
        //4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
        Thread t = new Thread(r);
        //5.调用Thread类中的start方法,开启新线程,执行run方法
        t.start();

        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"-->"+i);
        }
    }
}

实现Runnable接口的方式和继承Thread类方式不同

1:避免单继承的局限性
一个类继承了Thread类,就不能继承其他类
一个类实现了Runnable接口,还可以继承别的类,实现其他接口
2:增强了程序的扩展性
实现Runnable接口,把设置线程任务(重写run方法目的就是设置线程任务
和开启线程)和创建Thread对象(调用Start方法开启线程)
进行了解耦,分离

创建多线程程序的第三种方式:匿名内部类

匿名内部类作用:简化代码

把子类继承父类,重写父类方法,创建子类对象,合成一步完成
把实现类继承实现接口,重写接口的方法,创建实现类对象,合成一步完成
匿名内部类的方式实现多线程程序的三种方式:
父类Thread,new MyThread().start();

public class Demo01 {
    public static void main(String[] args) {
        //父类Thread
        //new MyThread().start();

        new Thread() {
            //重写run方法,设置线程任务
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+i);
                }
            }
        }.start();
    }
}

接口Runnable,new Thread(new RunnableImpl()).start() ;

public class Demo02 {
    public static void main(String[] args) {
        //接口Runnable
        //new Thread(new RunnableImpl()).start() ;

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 20; i++) {
                    System.out.println(Thread.currentThread().getName()+"-->"+i);
                }
            }
        }).start();
    }
}

Lambda 简化内部类

public class Demo03 {
    public static void main(String[] args) {
	//Lambda 简化内部类
        new Thread(()->{
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName()+"-->"+i);
            }
        }).start();
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

学习多线程,创建多线程的三种方式 的相关文章

  • 在 JTable 中移动行

    我使用 MVC 模式 并且有一个如下所示的 JTable List
  • ElasticBeanstalk Java,Spring 活动配置文件

    我正在尝试通过 AWS ElasticBeanstalk 启动 spring boot jar 一切正常 配置文件为 默认 有谁知道如何为 java ElasticBeanstalk 应用程序 不是 tomcat 设置活动配置文件 spri
  • AES 加密 Java/plsql

    我需要在Java和plsql DBMS CRYPTO for Oracle 10g 上实现相同的加密 解密应用程序 两种实现都工作正常 但这里的问题是我对相同纯文本的加密得到了不同的输出 下面是用于加密 解密过程的代码 Java 和 PLS
  • 如何测试 JUnit 测试的 Comparator?

    我需要测试 Compare 方法 但我对如何测试感到困惑 我可以看看该怎么做吗 public class MemberComparator implements Comparator
  • 线程自动利用多个CPU核心?

    假设我的应用程序运行 2 个线程 例如渲染线程和游戏更新线程 如果它在具有多核 CPU 当今典型 的移动设备上运行 我是否可以期望线程在可能的情况下自动分配给不同的核心 我知道底层操作系统内核 Android linux内核 决定调度 我的
  • manifest.mf 文件的附加内容的约定?

    Java JAR 中的 MANIFEST MF 文件是否有任何超出 MANIFEST MF 约定的约定 JAR规范 http download oracle com javase 1 4 2 docs guide jar jar html
  • CXF Swagger2功能添加安全定义

    我想使用 org apache cxf jaxrs swagger Swagger2Feature 将安全定义添加到我的其余服务中 但是我看不到任何相关方法或任何有关如何执行此操作的资源 下面是我想使用 swagger2feature 生成
  • 如何在 Java 中禁用 System.out 以提高速度

    我正在用 Java 编写一个模拟重力的程序 其中有一堆日志语句 到 System out 我的程序运行速度非常慢 我认为日志记录可能是部分原因 有什么方法可以禁用 System out 以便我的程序在打印时不会变慢 或者我是否必须手动检查并
  • 如何在jsp代码中导入java库?

    我有以下jsp代码 我想添加 java io 等库 我怎样才能做到这一点
  • Spring Data 与 Spring Data JPA 与 JdbcTemplate

    我有信心Spring Data and Spring Data JPA指的是相同的 但后来我在 youtube 上观看了一个关于他正在使用JdbcTemplate在那篇教程中 所以我在那里感到困惑 我想澄清一下两者之间有什么区别Spring
  • 制作java包

    我的 Java 类组织变得有点混乱 所以我要回顾一下我在 Java 学习中跳过的东西 类路径 我无法安静地将心爱的类编译到我为它们创建的包中 这是我的文件夹层次结构 com david Greet java greeter SayHello
  • 将 Long 转换为 DateTime 从 C# 日期到 Java 日期

    我一直尝试用Java读取二进制文件 而二进制文件是用C 编写的 其中一些数据包含日期时间数据 当 DateTime 数据写入文件 以二进制形式 时 它使用DateTime ToBinary on C 为了读取 DateTime 数据 它将首
  • 使用 AWS Java SDK 为现有 S3 对象设置 Expires 标头

    我正在更新 Amazon S3 存储桶中的现有对象以设置一些元数据 我想设置 HTTPExpires每个对象的标头以更好地处理 HTTP 1 0 客户端 我们正在使用AWS Java SDK http aws amazon com sdkf
  • org.jdesktop.application 包不存在

    几天以来我一直在构建一个 Java 桌面应用程序 一切都很顺利 但是今天 当我打开Netbeans并编译文件时 出现以下编译错误 Compiling 9 source files to C Documents and Settings Ad
  • Java中未绑定通配符泛型的用途和要点是什么?

    我不明白未绑定通配符泛型有什么用 具有上限的绑定通配符泛型 stuff for Object item stuff System out println item Since PrintStream println 可以处理所有引用类型 通
  • 使用 Flyway 和 Hibernate 的 hbm2ddl 在应用程序的生命周期中管理数据库模式

    我正在开发 Spring Hibernate MySql 应用程序 该应用程序尚未投入生产 我目前使用 Hibernatehbm2ddl该功能对于管理域上的更改非常方便 我也打算用Flyway用于数据库迁移 在未来的某个时候 该应用程序将首
  • 将 JTextArea 内容写入文件

    我在 Java Swing 中有一个 JTextArea 和一个 提交 按钮 需要将textarea的内容写入一个带有换行符的文件中 我得到的输出是这样的 它被写为文件中的一个字符串 try BufferedWriter fileOut n
  • KeyPressed 和 KeyTyped 混淆[重复]

    这个问题在这里已经有答案了 我搜索过之间的区别KeyPressedand KeyTyped事件 但我仍然不清楚 我发现的一件事是 Keypressed 比 KeyTyped 首先被触发 请澄清一下这些事件何时被准确触发 哪个适合用于哪个目的
  • java8 Collectors.toMap() 限制?

    我正在尝试使用java8Collectors toMap on a Stream of ZipEntry 这可能不是最好的想法 因为在处理过程中可能会发生异常 但我想这应该是可能的 我现在收到一个我不明白的编译错误 我猜是类型推理引擎 这是
  • javax.persistence.Table.indexes()[Ljavax/persistence/Index 中的 NoSuchMethodError

    我有一个 Play Framework 应用程序 并且我was使用 Hibernate 4 2 5 Final 通过 Maven 依赖项管理器检索 我决定升级到 Hibernate 4 3 0 Final 成功重新编译我的应用程序并运行它

随机推荐

  • scel转txt抽取词库

    最近需要词库来优化分词效果 找到了有大神写好的能将搜狗词库scel转成txt的python脚本 http blog csdn net zhangzhenhu article details 7014271 实际运行时因为python版本不同
  • Linux常用指令总结

    一 基础指令 1 ls 列出当前路径下的所有文件和目录的名称 ls l 以列表的形式展现所有 ls a 显示隐藏文件 ls h 将列出的文件大小以可读性较好的方式显示 默认单位为字节 文件大小过大 会以合适的单位来进行转化 但必须和 l 一
  • C++之对封装、继承、多态的理解

    目录 一 对封装 继承和多态的简单理解 二 举例 1 封装的例子 2 继承的例子 3 多态的例子 三 代码实现 1 封装 C 或Java实现 2 继承 C 或Java实现 3 多态 C 或Java实现 四 以一个简单的实例 剖析 封装 的实
  • C++ 按日期时间生成文件

    C 按日期时间生成文件 在日常开发环境中 需要按照时间去命名文件名 因此需要创建如年 月 日此类的字符串 这里给出例子 定义时间命名字符串的格式 enum FileNameStyle example 2022 07 11 14 54 27
  • 解决MSBUILD : error MSB3428错误

    问题 MSBUILD error MSB3428 未能加载 Visual C 组件 VCBuild exe 要解决此问题 1 安装 NET Framework 2 0 SDK 2 安装 Microsoft Visual Studio 200
  • java大津法确定阈值,大津法(最大类间阈值法)

    大津法又叫最大类间方差法 最大类间阈值法 OTSU 它的基本思想是 用一个阈值将图像中的数据分为两类 一类中图像的像素点的灰度均小于这个阈值 另一类中的图像的像素点的灰度均大于或者等于该阈值 如果这两个类中像素点的灰度的方差越大 说明获取到
  • tkinter批量循环创建按钮

    CourseList res courseList button list sy 20 for i in range len CourseList CourseList i CourseList i courseName CourseLis
  • 实现不同局域网间的文件共享和端口映射,使用Python自带的HTTP服务

    文章目录 1 前言 2 本地文件服务器搭建 2 1 python的安装和设置 2 2 cpolar的安装和注册 3 本地文件服务器的发布 3 1 Cpolar云端设置 3 2 Cpolar本地设置 4 公网访问测试 5 结语 1 前言 数据
  • Linux系统常用命令解读

    测试常用Linux进行得一些操作 查看日志 定位问题原因 修改配置文件中的一些配置进行测试 例如开关 文件存放路径 修改定时任务时间 查看服务器性能 远程登录工具 xshell winSCPC ll ls l 会列出该文件下的所有文件 文件
  • Linux生成UUID的算法方式(序列号C/C++代码实现)

    Linux中想获取机器的唯一标识 UUID 只需要在命令行中输入uuid就可以看到类似格式为 xxxxxxxx xxxx xxxx xxxxxxxxxxxxxxxx 8 4 4 16 机器标识 通过该唯一标识生成注册码 序列号 有了设备的唯
  • MySQL - 全文索引

    全文索引 英文查找 全文索引主要对字符串类型建立基于分词的索引 主要是基于CHAR VARCHAR和TEXT的字段上 以便能够更加快速地查询数据量较大的字符串类型的字段 全文索引以词为基础的 MySQL默认的分词是所有非字母和数字的特殊符号
  • 2022-04-20 Sass学习笔记(四) Sass的混入(mixin),继承(extend)和导入(import)

    1 Sass混入 mixin 与 include mixin 指令允许我们定义一个可以在整个样式表中重复使用的样式 include 指令可以将混入 mixin 引入到文档中 语法 定义 mixin mixin name 使用 selecto
  • 【华为OD机试真题 JAVA】连续出牌数量

    JS版 华为OD机试真题 JS 连续出牌数量 标题 连续出牌数量 时间限制 1秒 内存限制 262144K 语言限制 不限 有这么一款单人卡牌游戏 牌面由颜色和数字组成 颜色为红 黄 蓝 绿中的一种 数字为0 9中的一个 游戏开始时玩家从手
  • 【H5】 canvas图像各种合成详解

    本素材来源 https www cnblogs com hzj680539 p 5068487 html 尊重第一作者 把知识奉献给大家 简易直观图 黄色圆为原图 蓝色正方形为新图 红色圆为新图 蓝色为原图 globalCompositeO
  • 《SQLi-Labs》03. Less 11~15

    sqli 索引 Less 11 题解 原理 Less 12 题解 Less 13 题解 Less 14 题解 Less 15 题解 原理 sqli 开启新坑 索引 Less 11 POST 回显注入 字符型 Less 12 POST 回显注
  • 面试总结(六):搜索索引

    问题导读 1 如何理解用户输入查询语句 2 如何根据得到的文档和查询语句的相关性 对结果进行排序 3 如何计算权重 Term weight 过程 4 如何判断Term之间的关系从而得到文档相关性 搜索索引到这里似乎我们可以宣布 我们找到想要
  • 为什需要采用增广拉格朗日函数

    为什需要采用增广拉格朗日函数 目标函数的可以转化为Lagrangian函数的最小 称之为对偶函数 dual function d
  • moveit是如何控制机械臂运动的

    确定机械臂的状态 MoveIt会读取机械臂的当前状态 包括关节角度 位置和速度等信息 获取规划请求 MoveIt会接收到一个规划请求 其中包含了机械臂需要执行的任务和目标 进行运动规划 MoveIt会对机械臂的当前状态和任务目标进行运动规划
  • Jsvc

    Jsvc How to detach the Java daemon from the shell script Toolbox for IT Groups How to detach the Java daemon from the sh
  • 学习多线程,创建多线程的三种方式

    多线程 并发与并行 并发 两个或多个事件在同一个时间段内发生 交替执行 并行 两个或多个事件在同一个时刻发生 同时执行 进程与线程 进程 进入到内存中的程序 线程 进程中的一个执行单元 负责当前进程中程序的执行 一个进程中至少有一个线程 一