Java第二十章多线程

一、线程简介

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,这些线程可以并发执行。线程拥有自己的栈和局部变量,但是它们共享进程的其他资源,如全局变量、堆内存等。线程的优先级决定了线程需要时间片多少分配的线程属性。线程的启动和终止需要通过构造线程对象和调用start()方法来实现。

二、创建线程

1、继承Thread类

Thread类是java.lang包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要建立Thread实例。Thread类中常用的两个构造方法如下:

1.public Thread():创建一个新的线程对象。

2.public Thread(String threadName):创建一个名称为threadName的线程对象。

继承Thread类创建一个新的线程的语法如下:

public class ThreadTest extends Thread{
}

完成线程真正的功能的代码放在类的run()方法中,当一个类继承Thread类后,就可以在该类中覆盖run()方法,将实现该线程功能的代码写入run()方法中,然后调用Thread类中的start()方法执行线程,也就是调用run方法。

Thread对象需要一个人物来执行,任务是指线程在启动时执行的工作,该工作的功能代码被写在run方法中。run()方法必须使用以下语法格式:

public void run(){
}

注意:start()方法调用一个已经启动的线程,系统将抛出IllegalThreadStateException异常。

当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运行的。当不再启动其他线程时,该程序就为单线程程序,如本章以前的程序都是单线程程序。主方法线程启动由Java虚拟机负责,程序员负责启动自己的线程。代码如下:

public static void main(String[] args){
    new ThreadTest().start();
}

例题:让线程循环打印1~10的数字

start()方法会启动线程,线程自动执行run()方法中的代码,就可以看到for循环打印的数字了。

在main()方法中,使线程执行需要调用Thread类中的start()方法,start()方法调用被覆盖的run()方法,如果不调用start()方法,线程永远都不会启动,在主方法没有调用start()方法之前,Thread对象只是一个实例,而不是一个真正的线程。

2、实现Runnable接口

例题:让窗口中的图标动起来

三、线程的生命周期

线程具有生命周期,其中包含 7 种状态,分别为出生状态、就绪状态、运行状态、等待状态、眠状态、阻塞状态和死亡状态。出生状态就是线程被创建时处于的状态,在用户使用该线程实例调用start0方法之前线程都处于出生状态;当用户调用 start()方法后,线程处于就绪状态 (又被称为可执状态);当线程得到系统资源后就进入运行状态。
一旦线程进入可执行状态,它会在就绪与运行状态下转换,同时也有可能进入等待、休眠、阻塞或死亡状态。当处于运行状态下的线程调用 Thread 类中的wait0方法时,该线程便进入等待状态,进入等待状态的线程必须调用Thread类中的notify()方法才能被唤醒,而调用notifvAll()方法可将所有处于等待状态下的线程唤醒;当线程调用 Thread 类中的sleep()方法时,则会进入休眠状态。如果一个线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态,在其等待输入/输出结束时线程进入就绪状态,对于阻塞的线程来说,即使系统资源空闲,线程依然不能回到运行状态。当线程的run()方法执行完毕时,线程进入死亡状态。

四、操作线程的方法

1、线程的休眠

一种能控制线程行为的方法是调用sleep()方法,sleep()方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。在前面的实例中,已经演示过sleep()方法,它通常是在run()方法内的循环中被使用。sleep()方法的语法如下:

try{
        Thread.sleep(2000);
}catch(InterruptedException e){
        e.printStackTrace();
}

上述代码会使线程在2秒之内不会进入就绪状态。由于sleep()方法的执行有可能抛出InterruptedException异常,所以将sleep()方法的调用放在try-catch块中。虽然使用了sleep()方法的线程在一段时间内会醒来,但是并不能保证它醒来后进入运行状态,只能保证它进入就绪状态。

例题:每0.1秒绘制一条随机颜色的线条

        在本实例中定义了 getC()方法,该方法用于随机产生 Color 类型的对象并且在产生线程的匿名内部类中使用 getGraphics()方法获取 Graphics 对象,使用该对象调用setColor0方法为图形设置颜色。调用 drawLine()方法绘制一条线段,同时线段会根据纵坐标的变化自动调整。

2、线程的加入

        如果当前某程序为多线程程序,假如存在一个线程 A,现在需要插入线程 B,并要求线程B先执行完毕,然后再继续执行线程A,此时可以使用 Thread 类中的 join()方法来完成。这就好比此时读者正在看电视,突然有人上门收水费,读者必须付完水费后才能继续看电视。
        当某个线程使用 join()方法加入另外一个线程时,另一个线程会等待该线程执行完毕后再继续执行。下面来看一个使用 join()方法的实例。

例题:让进度条A等待进度条B

3、线程的中断

以往有的时候会使用stop()方法停止线程,但当前版本的JDK早已废除了stop()方法,不建议使用stop()=方法来停止一个线程的运行。现在提倡在run()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。

如果线程是因为使用了sleep()或wait()方法进入了就绪状态,可以使用Thread类中interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出InterruptedException异常,用户可以在处理该异常时完成线程的中断业务处理,如终止while循环。

例题:单击按钮停止进度条滚动

4、线程的礼让

Thread类中提供了一种礼让方法,使用yield()方法表示,它只是给当前正处于运行状态的线程一个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。

yield()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时会再度回到就绪状态。对于支持多任务的操作系统来说,不需要调用yield()方法,因为操作系统会为线程自动分配CPU时间片来执行。

五、线程的优先级

例题:观察不同优先级的线程执行完毕顺序

由于线程的执行顺序是由CPU决定的,即使线程设定了优先级也是作为CPU的参考数据,所以真实的运行结果可能并不一定按照优先级排序,例如笔者运行的结果如上。执行顺序为:D>C>B>A

六、线程同步

1、线程安全

实际开发中,使用多线程程序的情况很多,如银行排号系统、火车站售票系统等。这种多线程的程序通常会发生问题,以火车站售票系统为例,在代码中判断当前票数是否大于0,如果大于0则执行将该票出售给乘客的功能,但当两个线程同时访问这段代码时(假如这时只剩下一张票),第一个线程将票售出,与此同时第二个线程也已经执行完成判断是否有票的操作,并得出票数大于0的结论,于是它也执行售出操作,这样就会产生负数。所以,在编写多线程程序时,应该考虑到线程安全问题实质上线程安全问题来源于两个线程同时存取单一对象的数据。
例如,在项目中创建ThreadSafeTest类,该类实现了Runnable接口,在未考虑到线程安全问题的基础上,模拟火车站售票系统的功能的代码如下:

2、线程同步机制

例题:开发线程安全的火车售票系统

同步方法就是在方法前面用synchronized关键字修饰的方法,其语法如下:
synchronized void f(){}
当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为synchronized,否则就会出错。

修改例20.7的代码,将共享资源操作放置在一个同步方法中,代码如下:

nt num = 10:
public synchronized void doit() {//定义同步方法
    if(num>0){
        try{
                    Thread.sleep(10);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"————票数"+num--);
    }
}
public void run(){
    while(true){
        doit();
    }            //在run()方法中调用该同步方法
}

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

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

相关文章

STM32_10(I2C)

I2C通信 I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线两根通信线:SCL(Serial Clock)、SDA(Serial Data)同步,半双工带数据应答支持总线挂载多设备(一主多从…

网络和信息系统指令 ( NIS2 ) 及其全球影响

网络和信息系统指令 ( NIS2 ) 将于 2024 年 10 月生效,旨在提高欧盟 (EU) 的网络弹性。 不过,其影响可能会更广泛,带来更严格的流程和控制,并重新定义我们向被视为国家关键的组织提供服务的方式。 该强制性指令将具有效力&#x…

如果每天工资按代码行数来算,来看看你每天工资是多少

说在前面 😼😼如果每天的工资取决于我们所编写的代码行数,那么我们的生活会发生怎样的改变?来看看你的同事们今天都提交了多少代码吧,看看谁是卷王,谁在摸鱼(🐶🐶狗头保命…

利用Spring Boot构建restful web service的详细流程

本文档构建一个简单的restful webservice, 在官网原文Getting Started | Building a RESTful Web Service (spring.io)的基础上进行操作 文章目录 一、项目创建流程1.1 创建项目1.2 创建资源表示类1.3 创建资源控制类 二、项目运行参考资料 一、项目创建流程 本文的…

笔记61:注意力提示

本地笔记地址:D:\work_file\(4)DeepLearning_Learning\03_个人笔记\3.循环神经网络\第10章:动手学深度学习~注意力机制 a a a a a a a a

七、Lua字符串

文章目录 一、字符串(一)单引号间的一串字符(二)local str "Hello, "(三)[[ 与 ]] 间的一串字符(四)例子 二、字符串长度计算(一)string.len&…

RabbitMQ高级特性2 、TTL、死信队列和延迟队列

MQ高级特性 1.削峰 设置 消费者 测试 添加多条消息 拉取消息 每隔20秒拉取一次 一次拉取五条 然后在20秒内一条一条消费 TTL Time To Live(存活时间/过期时间)。 当消息到达存活时间后,还没有被消费,会被自动清除。 RabbitMQ…

服务器主机安全如何保障

随着互联网的快速发展,服务器主机安全问题日益凸显。服务器主机是网络世界中的核心,其安全性关乎着整个网络系统的稳定性和可靠性。 当前,服务器主机面临着多种安全威胁。其中,网络攻击是最为常见的一种。网络攻击者利用各种手段…

ELK+Filebeat

Filebeat概述 1.Filebeat简介 Filebeat是一款轻量级的日志收集工具,可以在非JAVA环境下运行。 因此,Filebeat常被用在非JAVAf的服务器上用于替代Logstash,收集日志信息。实际上,Filebeat几乎可以起到与Logstash相同的作用&…

Linux—进程状态

目录 一.前言 1.1.通过系统调用获取进程标示符 1.2.通过系统调用创建进程 二.进程状态 三.Z(zombie)-僵尸进程 四.僵尸进程危害 一.前言 学习进程的状态,我们首先了解一下进程的基本数据 1.1.通过系统调用获取进程标示符 由getpid(&#xff09…

多个nginx共享值、缓存问题

背景 目前我在集成登录认证功能(cas),使用的架构是nginxlua,由于我们有多个系统(全是前端项目),每套系统都采用nginxlua的方式进行部署(即每个系统都是一个nginx)&#…

pytorch读取tiny-imagenet-200的验证集(val)

ori_train torchvision.datasets.ImageFolder(root args.datadir /tiny-imagenet-200/train/, transformtransform)#可以获取class_idx的映射class_idx ori_train.class_to_idx val_annotations.txt中存储着每个图片对应的类别 获取验证集的标签 test_target []#读取val_…

java:jpa、Hibernate、Spring Data JPA、ORM以及和mybatis的区别

文章目录 Java连接数据库几种方式JPAHibernate和Spring Data JPAORM框架jpa和mybatis区别Spring Boot JPA使用例子1、创建库和表2、添加依赖3、配置数据源和Hibernate属性4、配置实体类5、创建一个继承JpaRepository的接口:6、创建一个控制器(Controller…

汽车电子 -- 车载ADAS之FCTA/FCTB(前方横向来车碰撞预警/制动)

参看:功能定义-前方交通穿行提示&制动 1、前方横向来车碰撞预警/制动 FCTA/FCTB( Front Cross Traffic Alert /Brake) 前方横向来车碰撞预警FCTA( Front Cross Traffic Alert ) 其功能表现为在车辆低速前进时&am…

解锁 ElasticJob 云原生实践的难题

发生了什么 最近在逛 ElasticJob 官方社区时发现很多小伙伴都在头疼这个 ElasticJob 上云的问题,ElasticJob 本就号称分布式弹性任务调度框架,怎么在云原生环境就有了问题了呢,这就要从 Kubenertes 和 ElasticJob 的一些状态化说起。 有意思的…

Java SE

目录 编程编的其实就是启动之后的内存⭐配置环境Java环境Windows配置Java环境变量Linux配置Java环境变量前言:常见Linux系统 Java基础类型八大基本数据类型数值型非数值型 void引用数据类型 运算符位运算符其他 基本结构表达式方法类实例(对象&#xff0…

战略制定|竞争战略管理分析六大常用工具

企业战略可从多个角度理解,体现为著名的5P模型。首先,从未来发展视角看,战略是一种计划(Plan),指导企业朝向既定目标前进。而从过去的发展历程看,它呈现为一种模式(Pattern),反映了企业的历史行为趋势。在产…

【Apifox】测试工具自动编写接口文档

在开发过程中,我们总是避免不了进行接口的测试, 而相比手动敲测试代码,使用测试工具进行测试更为便捷,高效 今天发现了一个非常好用的接口测试工具Apifox 相比于Postman,他还拥有一个非常nb的功能, 在接…

解决git action发布失败报错:Error: Resource not accessible by integration

现象: 网上说的解决方法都是什么到github个人中心setting里面的action设置里面去找。 可这玩意根本就没有! 正确解决办法: 在你的仓库页面,注意是仓库页面的setting里面: Actions> General>Workflow permisss…

dart多线程双向通信的案例----【小学4年级课程】

下面是运行后的打印顺序 I/flutter (20170): 上班 I/flutter (20170): 这里是校长室:main I/flutter (20170): 这里是饭堂:fantang1 I/flutter (20170): 这里是收发室--检查小孩发回去给他妈妈的信息是:我是秘书的儿子,我来到在校长室了。校长今晚想吃羊…