创建、运行线程,设置线程属性

2023-10-31

Java 9并发编程指南 目录

创建、运行线程,设置线程属性

a中有两种方式创建一个线程。

  • 继承Thread 类,重写run()方法。
  • 创建一个类,实现Runnable接口和run()方法,然后通过Runnable对象作为参数来创建Thread类的一个对象。优先考虑这种方式,灵活性很高。

在本节中,使用第二种方法创建线程。然后学习如何改变线程属性。线程类保存了一些信息属性来帮助我们识别一个线程,知道它的状态,或者控制其优先级。这些属性包括:

  • ID:每一个线程的唯一标识符。
  • Name:线程的名称。
  • Priority:线程对象的优先级。在Java 9中,线程的优先级在1到10之间,1的优先级最低、10的优先级最高。我们不需要改变线程的优先级,这只是作为底层操作系统的一个线索,不保证任何操作。
  • Status:线程的状态。在Java中,线程的状态定义在Thread.State枚举类型中,分别是NEW,RUNNABLE,BLOCKED,WAITING,TIME_WAITING,TERMINATED。分别介绍如下:
    • NEW:已创建线程,但并未开始运行;
      • RUNNABLE:线程已经在JVM上执行;
      • BLOCKED:线程阻塞,并且等待监控器分配;
      • WAITING:线程等待另一个线程运行完再执行;
      • TIMED_WAITING:线程在指定等待时间内等待另一个线程运行完再执行;
      • TERMINATED:线程执行完成。

在本节中,通过范例展现创建和运行10个计算20000以内质数个数的线程。

准备工作

本范例通过Eclipse开发工具实现。如果使用诸如NetBeans的开发工具,打开并创建一个新的Java项目。

实现过程

通过如下步骤完成范例:

  1. 创建名为Calculator的类,实现Runnable接口:

    public class Calculator implements  Runnable {
    
  2. 实现run()方法,这个方法执行创建的线程指令,计算20000以内的质数个数:

        @Override
        public void run() {
            long current = 1L;
            long max = 20000L;
            long numPrimes = 0L;
    
            System.out.printf("Thread '%s' : START\n" , Thread.currentThread().getName());
    
            while (current <= max){
                if (isPrime(current)) {
                    numPrimes++;
                }
                current ++;
            }
    
            System.out.printf("Thread '%s' : END. Number of Primes : %d\n" ,            Thread.currentThread().getName(), numPrimes);
        }
    
  3. 然后,实现辅助方法isPrime()。这个方法确定一个数字是否是质数:

        private boolean isPrime(long number) {
            if (number <= 2) {
                return true;
            }
            for (long i = 2; i < number; i++){
                if ((number % i) == 0){
                    return false;
                }
            }
            return true;
        }
    
  4. 现在实现主类。创建一个包含main()方法的Main类:

    public class Main {
        public static void main(String[] args){
    
  5. 首先,输出线程的最大、最小和默认优先级值:

            System.out.printf("Minimun Priority : %s\n" , Thread.MIN_PRIORITY);
            System.out.printf("Normal Priority : %s\n" , Thread.NORM_PRIORITY);
            System.out.printf("Maximum Priority : %s\n" , Thread.MAX_PRIORITY);
    
  6. 然后创建10个线程对象执行10个Calculator任务。同时,创建两个队列保存线程对象和它们的当前状态。随后会用这些信息检查这些线程终止。用最高优先级执行五个线程(偶数列),最低优先级执行另外五个线程:

            Thread threads[];
            Thread.State status[];
            threads = new Thread[10];
            status = new Thread.State[10];
            for(int i = 0 ; i < 10 ; i++){
                threads[i] = new Thread(new Calculator());
                if((i % 2) == 0) {
                    threads[i].setPriority(Thread.MAX_PRIORITY);
                }else{
                    threads[i].setPriority(Thread.MIN_PRIORITY);
                }
                threads[i].setName("My Thread " + i);
            }
    
  7. 将输出信息写入到文本文件中,所以创建try-with-resources声明来管理文件。在这段代码块中,在开始线程前将线程的状态记录到文件中,然后,启动线程:

            try(FileWriter file = new FileWriter(System.getProperty("user.dir")+"\\log.txt");
                        PrintWriter pw = new PrintWriter(file)) {
    
                for(int i =0 ; i < 10 ; i++){
                    pw.println("Main : Status of Thread " + i + " : " + threads[i].getState());
                    status[i] = threads[i].getState();
                }
    
                for(int i = 0 ; i < 10 ; i++) {
                    threads[i].start();
                }
    
  8. 这之后,等待线程结束。在本章“等待线程结束”的课程里,可以使用join()方法实现这个功能。由于我们需要在线程状态改变时记录下线程信息,所以不适用这个方法。使用如下代码块:

            boolean finish = false;
            while (!finish){
                for (int i = 0 ; i < 10 ; i++){
                    if(threads[i].getState() != status[i]) {
                        writeThreadInfo(pw, threads[i], status[i]);
                        status[i] = threads[i].getState();
                    }
                }
    
                finish = true;
                for(int i = 0 ; i < 10 ; i++){
                    finish = finish && (threads[i].getState() == Thread.State.TERMINATED);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    

  9. 在上述代码块中,调用writeThreadInfo()方法将线程状态信息记录到文件中。如下是这个方法实现代码:

    private static void writeThreadInfo(PrintWriter pw, Thread thread, Thread.State state){
        pw.printf("Main : Id %d - %s\n", thread.getId(), thread.getName());
        pw.printf("Main : Priority : %d\n" , thread.getPriority());
        pw.printf("Main : Old State : %s\n", state);
        pw.printf("Main : New State : %s\n" , thread.getState());
        pw.printf("Main : **************************************************\n");
    }
    
  10. 运行程序,查看不同的线程如何并行工作的。

工作原理

下面的截图展现程序在控制台输出的部分信息。可以看到所有创建的线程在同时执行它们各自的工作:
pics/01_01.jpg
在截图中,可以看到如何创建线程,以及偶数列线程因为有最高优先级而先执行,其他线程由于有最低优先级而后续执行。下面的截图显示输出的log.txt记录的部分线程状态信息。
pics/01_02.jpg
所有的Java程序都至少包含一个执行线程。当运行程序时,JVM运行程序中调用main()方法执行线程。

当调用Thread对象的start()方法时,将创建另一个执行线程。程序中包含与调用start()方法同样多的执行线程。

Thread类属性存储线程的所有信息。操作系统调度器始终通过线程优先级确定使用处理器的线程,同时根据当前情况实现每个线程的状态。

如果尚未给线程指定名称,JVM按照格式Thread-XX自动命名,其中XX是数字。我们无法修改线程的ID和状态,Thread类未实现setId()和setStatus()方法,因为这些方法在代码中实现修改操作。

当所有线程运行结束时(更具体的,当所有非守护线程运行结束时),Java程序才会终止。如果初始线程(执行main()方法的线程)终止,其他线程将继续执行之道结束。如果其中一个线程使用System.exit()指令来终止程序执行,所有的线程都将终止其各自执行。

在Thread类中创建对象,以及调用实现Runnable接口的类的run()方法都不会创建一个新的执行线程。只有调用start()方法时才会创建一个新的执行线程。

扩展学习

如本节介绍中提及的,还有一种创建执行线程的方法。继承Thread 类,重写run()方法。然后创建对象并调用start()方法获得一个新的执行线程。

通过Thread类的currentThread()方法使用正在运行当前对象的线程。

需要考虑的是,如果用setPriority()方法尝试设置线程优先级不在1-10之间,会抛出IllegalArgumentException异常。

更多关注

  • 本章中“工厂模式创建线程”小节。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建、运行线程,设置线程属性 的相关文章

  • HashMap不写入数据库

    我尝试在我的数据库中写入 但只写入发件人和消息 我不明白为什么会发生这种情况 我认为问题出在我使用 sendMessage 的地方 我认为问题是我没有什么可以做的读 写其他用户的主键 我在数据库中写入消息的活动 public class M
  • 无法解析类型为 xxx 的任何 bean;限定符:[@javax.enterprise.inject.Any()]

    我有一个 LoginProvider 接口 public interface LoginProvider boolean login String username String password 以及两种不同的实现 public clas
  • 添加动态数量的监听器(Spring JMS)

    我需要添加多个侦听器 如中所述application properties文件 就像下面这样 InTopics Sample QUT4 Sample T05 Sample T01 Sample JT7 注意 这个数字可以多一些 也可以少一些
  • 对话框上的 EditText 不返回任何文本

    我太累了 找不到错误 我没有发现任何错误 但我没有从 editText 收到任何文本 请看下面的代码 活动密码 xml
  • Android 自定义视图不能以正确的方式处理透明度/alpha

    我正在绘制自定义视图 在此视图中 我使用两个不同的绘画和路径对象在画布上绘画 我基本上是在绘制两个重叠的形状 添加 Alpha 后 视图中重叠的部分比图像的其余部分更暗 这是不希望的 但我不知道如何解决它 这是我的代码片段 用于展示我如何在
  • 记录骆驼路线

    我的项目中有几个 Camel 上下文 如果可能的话 我想以逆向工程方式记录路线 因为我们希望保持与上下文相关的文档最新 最好的方法是什么 我们倾向于预先实际设计路线 并使用来自EIP book http www eaipatterns co
  • 内存一致性 - Java 中的happens-before关系[重复]

    这个问题在这里已经有答案了 在阅读有关内存一致性错误的 Java 文档时 我发现与创建 发生 之前 关系的两个操作相关的点 当语句调用时Thread start 每个具有 与该语句发生之前的关系也有一个 与 new 执行的每个语句之间发生的
  • 如何在android中设置多个闹钟,在这种情况下最后一个闹钟会覆盖以前的闹钟

    我正在开发一个Android应用程序 用户可以在其中设置提醒时间 但我在以下代码中遇到一个问题 即最后一个警报会覆盖之前的所有警报 MainActivity java public void setreminders DatabaseHan
  • Java 服务器-客户端 readLine() 方法

    我有一个客户端类和一个服务器类 如果客户端向服务器发送消息 服务器会将响应发送回客户端 然后客户端将打印它收到的所有消息 例如 如果客户端向服务器发送 A 则服务器将向客户端发送响应 1111 所以我在客户端类中使用 readLine 从服
  • 隐式超级构造函数 Person() 未定义。必须显式调用另一个构造函数?

    我正在开发一个项目 但收到错误 隐式超级构造函数 Person 未定义 必须显式调用另一个构造函数 我不太明白它 这是我的人物课程 public class Person public Person String name double D
  • 无法加载或查找主类,可以在命令行中使用,但不能在 IDE 中使用[重复]

    这个问题在这里已经有答案了 在将其标记为重复之前 请先听我说完 我正在尝试使用 gradle 导入一个 java 项目 功能齐全 适用于所有其他笔记本电脑 没有问题 我的项目 100 正常运行 适用于所有其他笔记本电脑 当我的笔记本电脑被重
  • 计算日期之间的天数差异

    在我的代码中 日期之间的差异是错误的 因为它应该是 38 天而不是 8 天 我该如何修复 package random04diferencadata import java text ParseException import java t
  • Java - 返回值是否会中断循环?

    我正在编写一些基本上遵循以下格式的代码 public static boolean isIncluded E element Node
  • Spring Security OAuth2简单配置

    我有一个简单的项目 需要以下简单的配置 我有一个 密码 grant type 这意味着我可以提交用户名 密码 用户在登录表单中输入 并在成功时获得 access token 有了该 access token 我就可以请求 API 并获取用户
  • 如何配置 WebService 返回 ArrayList 而不是 Array?

    我有一个在 jax ws 上实现的 java Web 服务 此 Web 服务返回用户的通用列表 它运行得很好 Stateless name AdminToolSessionEJB RemoteBinding jndiBinding Admi
  • Espresso 和 Proguard 的 Java.lang.NoClassDefFoundError

    我对 Espresso 不太有经验 但我终于成功地运行了它 我有一个应用程序需要通过 Proguard 缩小才能处于 56K 方法之下 该应用程序以 3 秒的动画开始 因此我需要等到该动画结束才能继续 这就是我尝试用该方法做的事情waitF
  • 对象锁定私有类成员 - 最佳实践? (爪哇)

    I asked 类似的问题 https stackoverflow com questions 10548066 multiple object locks in java前几天 但对回复不满意 主要是因为我提供的代码存在一些人们关注的问题
  • Java的-XX:+UseMembar参数是什么

    我在各种地方 论坛等 看到这个参数 并且常见的答案是它有助于高并发服务器 尽管如此 我还是找不到 sun 的官方文档来解释它的作用 另外 它是Java 6中添加的还是Java 5中存在的 顺便说一句 许多热点虚拟机参数的好地方是这一页 ht
  • 嵌入式 Jetty - 以编程方式添加基于表单的身份验证

    有没有一种方法可以按如下方式以编程方式添加基于表单的身份验证 我用的是我自己的LdapLoginModule 最初我使用基本身份验证并且工作正常 但现在我想在登录页面上进行更多控制 例如显示徽标等 有没有好的样品 我正在使用嵌入式 jett
  • Android 和 Java 中绘制椭圆的区别

    在Java中由于某种原因Ellipse2D Double使用参数 height width x y 当我创建一个RectF在Android中参数是 left top right bottom 所以我对适应差异有点困惑 如果在 Java 中创

随机推荐

  • ARouter 基础使用详解

    文章目录 参考资料 配置ARouter 初始化与销毁 初始化 销毁 路由注解与跳转 Activity之间的跳转 路径定义 代码示例 Fragment之间的切换 Fragment注入路由 Fragment的获取与切换 带参数的跳转 示例代码
  • Springboot yml 复杂对象的二维数组

    有两种形式可以表达这种需求 一 通过建立一个二维维数组来表述 1 Grid类 Data AllArgsConstructor NoArgsConstructor public class Grid Long x 栅格中心位置 x 值 Lon
  • 挖矿病毒排查并清除

    近期 公司内网linux环境出现了挖矿病毒 该病毒占满cpu进行挖矿 导致系统缓慢 现摸索了以下步骤进行清除 1 检测服务器是否有挖矿病毒 使用top命令查看进程及占用cpu百分比 如果该进程名称为随机字符串 且cpu占的非常的高 则很可能
  • OSPF篇——SPF算法——002

    目录 最短路径优先算法 SPF 阶段1 构建SPF树 阶段2 计算最优路由 最短路径优先算法 SPF 在一类LSA和二类LSA中 包括了拓扑信息和路由信息 OSPF将依据SPF算法和各类LSA LSA内既包含拓扑信息又包含路由信息 但是分开
  • 关于VS Code 断点失效(断点变空心)

    问题 VS code 断点再有的文件中能正常使用 有的文件中打断点会变成灰色空心 这部分代码没问题能正常运行 但是断点失效无法重断点处停下来 解决方案 1 百度查看相似案例解决方案 2 这是我的问题解决方法 查看代码是否有问题 VScode
  • linux系统之字符设备驱动——DS18B20温度传感器

    linux系统之字符设备驱动 DS18B20温度传感器 1 原理图 2 驱动程序 驱动程序 ds18b20 c Author your name Date 2021 02 06 19 41 29 LastEditTime 2021 02 2
  • css根据内容自动调整td高度,css – 如何使div高度100%内部td的100%

    这个问题似乎在stackoverflow上至少有10次 但是其中一个实际上没有答案 这一点略有不同 因为问题出现在Firefox中 我的桌子高度为100 高度为100 我把td的边界设置成可以看到的东西 我看到td是预期的100 我把一个d
  • JS前端点击记住密码之后再次登录时显示账号密码

    一 前端html代码 div div
  • Nacos下载与安装详解

    目录 一 安装与下载 二 数据持久化 三 docker当中安装nacos 一 安装与下载 下载地址 https github com alibaba nacos releases 我这里下载的windows版本的 不需要安装 下载好直接解压
  • requests.exceptions.InvalidHeader: Value for header {XX: (‘XX‘,)} must be of type str or bytes, not

    requests exceptions InvalidHeader Value for header xxx xxx must be of type str or bytes not
  • Http协议及各版本对比

    前言 本文主要简单介绍http协议发展的历史版本以及https的安全机制 对于更多深入协议内层及网络通信相关的知识 在此暂不做总结 何谓Http协议 超文本传输协议 Hypertext Transfer Protocol HTTP 是一个简
  • echart单系列柱状图增加配置筛选legend

    先看整体效果图 这边简单说下实现思路 单列柱子在官网demo是没有legend的 但是多列柱子是有的 因此 我们可以让单列柱子变成多列柱子的集合 然后集合里面只有一列是有data的 相当于是这样的集合 0 1 0 然后使用重叠配置 把那些空
  • 安卓9.0适配方案和踩坑

    年初的时候就已经适配了安卓9 0 但由于业务需求一直没有使用上 前段时间发布了 结果有用户反馈在安卓9 0的手机上更新下载App发生了闪退 这个时候发现9 0对权限 加密和Apache HTTP client发生了相关变化 一 首先我遇到的
  • matlab解决线性规划

    线性规划 线性规划 Linear programming 简称LP 是运筹学中研究较早 发展较快 应用广泛 方法较成熟的一个重要分支 它是辅助人们进行科学管理的一种数学方法 研究线性约束条件下线性目标函数的极值问题的数学理论和方法 英文缩写
  • 数据库间歇性失败 OERR: ORA-12519

    ORA 12519 TNS 没有找到适用的服务处理 OERR ORA 12519 TNS no appropriate service handler found 客户端连接间歇性失败 报错ORA 12519 Oracle客户端与服务器之间
  • select、poll、epoll之间的区别(搜狗面试)(转载)

    1 select gt 时间复杂度O n 它仅仅知道了 有I O事件发生了 却并不知道是哪那几个流 可能有一个 多个 甚至全部 我们只能无差别轮询所有流 找出能读出数据 或者写入数据的流 对他们进行操作 所以select具有O n 的无差别
  • 云服务器文件打包,如何把云服务器的文件打包出来

    如何把云服务器的文件打包出来 内容精选 换一换 文档数据库服务支持开启公网访问功能 通过弹性IP进行访问 您也可通过弹性云服务器的内网访问文档数据库 要将已有的MongoDB数据库迁移到文档数据库 需要先使用mongoexport工具对它做
  • boa的cgi使用总结

    相关配置 配置ScriptAlias 虚拟路径 真实路径 ScriptAlias cgi bin etc boa www cgi bin 指明CGI脚本的虚拟路径对应的实际路径 一般所有的CGI脚本都要放在实际路径里 用户访问执行时输入站点
  • 如何让 uni-app 页面中的背景图片高度和宽度自适应

    如何让 uni app 页面中的背景图片高度和宽度自适应 在今天做项目的时候突然遇到一个问题 我给页面加一个背景图片 但是当页面高度超过100 时 图片会覆盖不到 如图所示 写的代码是这样的 错误的代码 App vue 页面
  • 创建、运行线程,设置线程属性

    Java 9并发编程指南 目录 创建 运行线程 设置线程属性 准备工作 实现过程 工作原理 扩展学习 更多关注 a中有两种方式创建一个线程 继承Thread 类 重写run 方法 创建一个类 实现Runnable接口和run 方法 然后通过