Java 多线程的创建

Java 多线程的创建

Java元的JVM允许程序运行多个线程,使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类

线程的创建方式有两种,一者为继承Thread类,一者为实现Runnable接口

实现方式之一:继承Thread类

实现步骤

Java通过继承Thread类来创建启动多线程的步骤如下:

  • 创建一个继承于Thread
  • 重写Thread类的run() 将此线程要执行的操作,生命在此方法体中
  • 创建当前Thread 的子类的对象
  • 通过对象调用start() —>1. 启动线程 2.调用当前线程的run()方法

创建一个分线程1,用于遍历100日内的偶数

class PrintNumber extends Thread{@Override重写Thread类中的run()方法  ---->将此线程要执行的操作,声明在方法体中public void run() {for(int i=0;i<=100;i++){if(i % 2 == 0){System.out.println(i);}}}
}public class NumberTest{public static void main(String []args){//创建当前Thread的子类的对象PrintNumber t1 = new PrintNumber();//通过对象调用start()方法   start是父类Thread中的方法t1.start();}
}//API中start()的描述
//Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
//启动线程,JVM会调用当前线程的run()方法

分线程会和main()并发进行,改动后

public class ThreadTest {public static void main(String[] args) {OneThread o1 = new OneThread();o1.start();for(int i = 0; i< 1000000; i++){System.out.println("这是main方法");}}
}class OneThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 1000000; i++) {System.out.println("这是OneThread");}}
}
//当运行此程序时,输出为
//这是main方法 与 这是OneThread 交叉输出 
//也可以使用Thread.currentThread().getName()直观的输出 该线程的名称

深入思考

问题一

run()方法已经重写,并且run()方法中是分线程所需要执行的操作,那能否使用run()方法替换start()方法的调用,实现分线程的创建和调用?

不能,如果这样使用,则不会创建多线程,就相当于一个普通的方法

示例

public class ThreadTest {public static void main(String[] args) {OneThread o1 = new OneThread();o1.start();for(int i = 0; i< 1000000; i++){System.out.println(Thread.currentThread().getName());}}
}class OneThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 1000000; i++) {System.out.println(Thread.currentThread().getName());}}
}//输出结果(节选)
Thread-0
Thread-0
Thread-0
main
main
main
main

更改之后

public class ThreadTest {public static void main(String[] args) {OneThread o1 = new OneThread();o1.start();for(int i = 0; i< 1000000; i++){System.out.println(Thread.currentThread().getName());}}
}class OneThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 1000000; i++) {System.out.println(Thread.currentThread().getName());}}
}
//输出结果(节选)
main
main
main
//此时,全是main方法中的线程,相当于调用了一个普通类的普通方法,并不是多线程
问题二

能否在提供一个线程,用于输出偶数?

class PrintNumber{public void run(){for(int i = 0; i< 100 ;i++){if(i % 2 == 0){System.out.println(i);}}}
}public class NumberTest{public static void main(String []args){PrintNumber p1 = new PrintNumber();p1.start();p1.start();}
}
//输出结果
0 - 100的 偶数(省略)
Exception in thread "main" java.lang.IllegalThreadStateExceptionat java.base/java.lang.Thread.start(Thread.java:1525)at 多线程.EvenNUmberTest.main(EvenNUmberTest.java:9)

不能让已经start()的线程再次执行star()方法,否则报异常。非法的线程状态。

若想要再次提供一个线程,可以再实例化一个对象,用这个对象调用start()方法

问题三

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

public class NumberTest {public static void main(String[] args) {EvenNumberPrint t1 = new EvenNumberPrint();OddNumberPrint t2 = new OddNumberPrint();t1.start();t2.start();}
}class EvenNumberPrint extends Thread{   //用于打印偶数@Overridepublic void run() {for (int i = 0; i <= 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName()+" "+i);}}}
}
class OddNumberPrint extends Thread{    //用于打印奇数@Overridepublic void run() {for (int i = 0; i <= 100; i++) {if(i % 2 != 0){System.out.println(Thread.currentThread().getName()+" "+ i);}}}
}

实现方式之一 :实现Runnable接口

实现步骤

以下为实现Runnable接口的具体步骤

  • 创建一个实现Runnable接口的类
  • 实现接口中的run()方法 ——> 将此线程要执行的操作,声明在run()方法体中
  • 创建当前实现类的对象
  • 将此对象作为参数传递到Thread类中的构造器中,创建Thread类的实例
  • Thread类的实例调用start()方法。start的作用 ①启动线程②调用run()方法

普通方式

public class EvenNumberTest {public static void main(String[] args) {//创建当前类的实例化EvenNumberPrint p = new EvenNumberPrint();//将此对象作为参数传递到Thread类的构造器中Thread t1 = new Thread(p);t1.start();}
}class EvenNumberPrint implements Runnable{@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName() +" "+ i);}}
}//输出结果
//
Thread-0 0
Thread-0 1.....省略
Thread-0 100

使用接口匿名实现类的匿名对象

//使用实现Runnable接口的方式,提供了Runnable接口匿名实现类的匿名对象
public class EvenNumberTest {public static void main(String[] args) {new Thread(new Runnable(){public void run(){for(int i = 0; i < 100 ; i++){System.out.println(Thread.currentThread().getName() + i);}}}).start();}
}

两种实现方式的对比

共同点

  • 启动线程时,使用的都是Thread类中定义的start()
  • 创建的线程对象,都是Thread类或其子类的实例

不同点

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

建议

建议使用实现Runnable接口的实现。

  • 可以避免类的单继承的局限性
  • 更适合处理有共享数据的问题
  • 实现了代码和数据的分离

两种方式的联系

查看Thread的源码会发现,Thread类 也是实现了Ruunable接口

public class Thread implements Runnable {    }

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

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

相关文章

【LeetCode算法】第111题:二叉树的最小深度

目录 一、题目描述 二、初次解答 三、官方解法 四、总结 一、题目描述 二、初次解答 1. 思路&#xff1a;二叉树的先序遍历。求出左子树的最小高度&#xff0c;求出右子树的最小高度&#xff0c;最终返回左子树和右子树的最小高度1。关键&#xff1a;若左子树的高度为0&…

【Linux】命名管道

一、命名管道的原理 在前面的博客中&#xff0c;我们学习了匿名管道&#xff0c;了解到了两个具有血缘关系的进程之间是如何进行通信的&#xff1f;那么在没有血缘关系&#xff08;毫不相关&#xff09;的进程之间是如何进行通信的&#xff1f; 大致思路是一样的&#xff0c;我…

重构与优化-组织数据(3)

重构组织数据是一个系统性的工程,旨在改进数据的存储方式、访问效率、质量和可用性,以更好地支持业务运营、分析决策和未来发展。以下是重构组织数据的一些关键说明点: 目的与动机 提升效率:通过优化数据结构、减少冗余数据和改善索引策略,加快数据查询和处理速度。 增强…

FCA-FineReport 试题及答案

第1题【判断题】服务器安装插件支持热部署&#xff0c;安装、删除、更新、禁用、启用不需要重启 A. 正确 B. 错误 正确答案&#xff1a;A 第2题【判断题】普通用户登录到决策系统平台与管理员登录界面相同 A. 正确 B. 错误 正确答案&#xff1a;A 第3题【判断题】用户管理可…

JavaScript倍速播放视频

F12打开开发者工具&#xff0c;打开控制台&#xff0c;输入这行代码&#xff0c;视频即可加速播放&#xff0c; 可以调整倍速&#xff08;2&#xff0c;4&#xff0c;8&#xff0c;16&#xff09; document. getElementsByTagName("video")[0]. playbackRate16

实现JDBC编程

JDBC编程 JDBC —> java database connectivity 即java数据连接, 是执行sql语句的javaAPI(application programming interface),所谓的数据库是一类软件,就会提供对应的API,数据库有很多种,不同的数据库提供对应的API是不一样的,而这个API有java.sql.* 和 javax.sql.*包中的…

【数据挖掘】3σ原则识别数据中的异常值(附代码)

写在前面&#xff1a; 首先感谢兄弟们的订阅&#xff0c;让我有创作的动力&#xff0c;在创作过程我会尽最大能力&#xff0c;保证作品的质量&#xff0c;如果有问题&#xff0c;可以私信我&#xff0c;让我们携手共进&#xff0c;共创辉煌。 路虽远&#xff0c;行则将至&#…

机关——用钥匙开对应的门

代码展示 玩家背包代码&#xff08;挂载到玩家身上&#xff09; using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 玩家背包脚本&#xff0c;用来记录玩家道具 /// </summary> public class MyBag : MonoBeha…

03DDL语言的使用

03DDL语言的使用 第1关&#xff1a;创建数据库任务描述相关知识连接数据库创建数据库 答案 第2关&#xff1a; 创建表任务描述相关知识 答案 第3关&#xff1a;添加字段任务描述相关知识添加字段编程要求 答案 第4关&#xff1a;删除字段任务描述相关知识编程要求 答案 第5关&a…

pytorch学习笔记4

开启tensorboard 在terminal中输入tensorboard --logdir文件名 文件名中不能含有空格 tensorboard --logdirlogs --port6007#将端口调整为6007tensorboard --logdirlogs --port 0 自动分配一个端口&#xff0c;成功访问打开的时候如果发现没数据可以把logs换成文件夹的绝对路径…

【儿童节特辑】用AI创造音乐,变身小小音乐家!

在儿童节这个充满欢笑的日子里&#xff0c;让我们一起探索如何用AI技术为孩子们准备一份特别的礼物——一张由AI生成的音乐专辑。&#x1f3b5;✨ &#x1f3bc; 文字变旋律&#xff1a;开启音乐创作之旅 想象一下&#xff0c;只需一段文字&#xff0c;就能编织出一曲悠扬悦耳…

Python自动实时查询预约网站的剩余名额并在有余额时发邮件提示

本文介绍基于Python语言&#xff0c;自动、定时监测某体检预约网站中指定日期的体检余额&#xff0c;并在有体检余额时自动给自己发送邮件提醒的方法。 来到春招末期&#xff0c;很多单位进入了体检流程。其中&#xff0c;银行&#xff08;尤其是四大行&#xff09;喜欢“海检”…

Day44 动态规划part04

背包问题 01背包问题&#xff1a;每件物品只能用一次完全背包问题&#xff1a;每件物品可以使用无数次 01背包问题 暴力解法&#xff1a;每一件物品其实只有两个状态&#xff0c;取或者不取&#xff0c;所以可以使用回溯法搜索出所有的情况&#xff0c;那么时间复杂度就是 o…

Transformer从0到1的学习【还有2-10,别想太多】

1.高纬度介绍Transformer 1.分为编码Encoders和解码器Decoders&#xff1a;“我爱你”作为编码器Encoders的输入进行编码得到序列码后&#xff0c;作为解码器的输入得到输出即为&#xff0c;“I Love you”。 2.编码器和译码器的具体拆分&#xff1a; 左边的编码器Encoders的…

Pytorch实用教程:pytorch中nn.Linear()用法详解 | 构建多层感知机 | nn.Module的作用 | nn.Sequential的作用

文章目录 1. nn.Linear()用法构造函数参数示例使用场景2. 构建多层感知机步骤代码示例注意事项3. 继承自nn.Module的作用是什么?1. 组织网络结构2. 参数管理3. 模型保存和加载4. 设备管理不继承 `nn.Module` 的后果

【常见的六大排序算法】插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序

个人主页 创作不易&#xff0c;感谢大家的关注&#xff01; 文章目录 前言 &#x1f3a1;一、插入排序&#x1f332;二、希尔排序&#x1f389;三、选择排序&#x1f380;四、冒泡排序&#x1f698;五、堆排序&#x1f6f5;六、快速排序1. Hoare版本2. 挖坑法3. 前后指针法4. 非…

详解 Spark 核心编程之 RDD 分区器

一、RDD 分区器简介 Spark 分区器的父类是 Partitioner 抽象类分区器直接决定了 RDD 中分区的个数、RDD 中每条数据经过 Shuffle 后进入哪个分区&#xff0c;进而决定了 Reduce 的个数只有 Key-Value 类型的 RDD 才有分区器&#xff0c;非 Key-Value 类型的 RDD 分区的值是 No…

头歌动态分区算法第2关:最佳适应算法

编程要求 空闲分区采用带头结点的双向链表来管理,主函数、链表初始化函数和打印函数已实现,只需要补充最佳适应算法分配内存的函数 best_fit以及内存回收的函数recycle()即可。 bool best_fit(int id,int m_size)//使用最佳适应算法给作业分配内存,id为作业号,m_size为作业…

大佬推荐的好用网盘工具

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 前段时间有大佬推荐了一款网盘工具seafile&#xff0c;自己搭建起来试用了一下&#xff0c;发现还挺好用的&#xff0c;这款工具…

【C++】C++11新特性:新的类功能、可变参数模板、STL容器中的empalce相关接口函数、lambda表达式、包装器(function、bind)

目录 一、新的类功能 1.1 移动构造函数和移动赋值运算符重载 1.2 强制生成默认函数的关键字default 1.3 禁止生成默认函数的关键字delete 1.4 其它的类功能 二、可变参数模板 三、STL容器中的empalce相关接口函数 四、lambda表达式 4.1 lambda的引入 4.2 lambda表达式…