目录
一、实验目的
二、实验内容
三、实验小结
一、实验目的
1、 了解线程的调度和执行过程,掌握Java 语言中多线程编程的基本方法
2、 掌握Runnable 接口实现多线程的方法
3、 掌握Thread 类实 现多线程的用法
二、实验内容
采用多线程机制模拟汇款业务。定义一银行类可接受顾客的汇款,其属性count用于存储账户金额。现有两名顾客,每人分三次、每次100元将钱汇入count。每进行一次汇款,便输出汇款人和账户总额。
算法描述及实验步骤:
①首先定义一个银行类并实现Runnable接口的run()方法,作为两个顾客线程的目标对象用于顾客存钱的银行。
②在银行类中创建一个count实例变量用于存放顾客汇款总钱数。
③在银行类中实现run()方法并使用循环的机制来模拟每人三次汇款的情况,然后使用println()方法输出每次顾客汇款的情况。
④在主类中创建两个顾客线程并将银行类的实例作为其两个线程去银行存钱的目标对象。
⑤使用setName()方法为两个顾客线程起名字。
⑥最后,使用start()方法启动两个顾客线程模拟去银行汇款。
源代码:
实验运行截图:
三、实验小结
1、编写好的未运行的代码就是程序,一但编写好的代码程序被运行起来就是进程。线程被包含在进程之中,依附于进程是进程处理多任务的其中一个任务分支,线程只要被开启,便不在依附于产生它的父线程,自己会经历从产生、运行、中断到死亡的过程。
2、多线程就是一个程序中包含多个线程,用于分别处理不同的任务。线程一旦被开启,便会进入就绪队列排队等候Java虚拟机轮询反复将计算机CUP的使用权切换给队列中的其中一个线程。线程一旦获得CUP的使用权便会自动执行自身的run()方法中编写的任务。一旦分配给正在运行的线程CUP时间用完,不管此线程方法中的任务代码是否执行完毕,Java虚拟机都会自动将CUP的使用权切换给下个排队等候的线程去执行其代码。
3、每个线程都有自身的生命周期和状态。如:
- 新建状态NEW:Thread类获其子类一旦创建线程对象,此时的线程便是新建状态,新建状态位于线程被创建到开启线程之前。
- 可运行状态RUNNABLE:线程对象一旦调用start()方法便会进入就绪队列排队等候CUP的使用权,此时的线程也会从新建状态切换到可运行状态。
- 中断状态(BLOCKED、WAITING、TIMED_WAING):
BLOCKED: 正在使用CUP运行的线程一旦被Java虚拟机将cup的使用权切换给其他的线程,此线程便会从可运行状态切换到阻塞状态,直到Java虚拟机再次将cup的使用权切换给此进程,状态才会变回可运行状态。
WATING:正在使用cup执行方法的线程,一旦在其执行代码期间调用wait()方法,此线程便会中止执行并将cup的使用权让给其他的线程,除非其他的线程调用notifyAll()方法,等待中止运行的线程才能恢复到可运行状态重新等待使用cup执行代码。
TIMED_WAING: 正在使用cup执行的线程一旦调用Thread.sleep()方法,便会进入休眠状态。在非同步方法线程中,此时线程将中止运行并让出cup的使用权给其他的线程;若是在同步方法中,此线程虽然也会中止运行但并不会让出cup的使用权,休眠时间结束此线程便会接着运行。
- 死亡状态TERMINATED:线程的任务方法一旦执行完毕或者返回,便会进入死亡状态,表明此线程需要处理的任务执行完毕不在排队使用CUP资源。
4、进入就绪队列排队等候使用cup的线程都会有优先级,其范围1~10越大越优,默认线程的优先级为5。处于高优先级的线程将先使用cup的资源,同等优先级的线程则排队等待轮流使用cup的资源,直到其优先级的线程都执行完毕或返回,低优先级的线程才使用cup的资源。setPriority(int grade)方法设置线程的优先级,getPriority()返回线程的优先级。
5、线程的创建有两种方法,其中:
- 使用Thread类的子类创建线程。子类中必须重写Thread线程类中的run()方法来指定子类创建的线程要执行的任务代码。
- 使用Thread(Runnable target)类直接创建线程。必须是实现Runnable接口的类的对象才能作为线程的目标参数即目标对象。创建的线程会与目标对象绑定,一旦线程获取到cpu的使用权便会自动调用目标对象中的run()方法执行线程的任务。其中有两种方式:①声明创建的线程不是目标对象类中的成员变量②声明创建的线程是目标对象所在类中的成员变量。可以使用“线程.setName(String name)”方法给线程起名字,使用”Thread.currentThread().getName()”方法获取目前使用cup的线程名。
- 一个线程对应一个run()方法,即使线程都指向同一个目标对象也是如此。
6、线程常用方法如下:
- start()开启线程。使线程从新建状态进入可运行状态(就绪队列)排队等候使用cpu资源
- run()定义线程对象被调用之后执行的操作任务。Thread的子类创建的线程必须重写Thread父类中的run()方法。
- sleep(毫秒)线程调用此方法会放弃cpu的使用权中止运行,进行休眠状态,待到时间结束或被其他线程吵醒则休眠结束再次排队等候cpu的使用权。休眠期间cpu的使用权会不会被其他线程使用要看sleep()方法使用的场景。
- isAlive() 判断线程是否处于就绪队列排队使用cpu资源即存活阶段。线程未启动或处于死亡状态都返回false。
- currentThread()获取当前正在使用cpu资源的线程对象。
- interrupt()休眠的线程对象调用此方法会吵醒休眠的线程让其触发interruptedException异常,从而结束休眠,排队等候使用cpu。
7、线程同步就是多个线程都使用同一个用synchronized修饰的同步方法。一个线程只有执行完同步方法或返回后其他的线程才能使用此同步方法。即同步方法在某个线程使用期间不允许其他的线程调用即使当前线程处于休眠状态也不会让出cpu的使用权,除非同步方法执行完毕,当前线程结束。有点类似文件锁。
8、在同步方法中正在运行的线程可以调用wait()方法来中止本线程的执行,让出cpu的使用权,使本线程处于等待状态,在此期间允许其他的线程使用同步方法;待其他线程执行完同步方法后并使用notifyAll()方法通知处于等待的线程结束等待后,其他等待中断的线程才能重新从中断处继续执行(遵循:先中断先继续原则)。
9、一个正在执行的线程可以让其他线程调用join()方法来与本线程联合。当前线程一旦和其他线程联合,本线程将中止运行直到联合的线程执行完毕或返回后,本线程才会排队等候cpu使用权接着运行。
10、在GUI图形编程中,程序一旦执行便会自动产生许多线程,其中AWT-EventQuecue线程负责处理组件触发的事件即执行监视器对象调用其事件处理的方法。AWT-Windows线程负责将窗体或组件绘制到桌面。组件一旦触发事件,Java虚拟机便会立刻将cpu的使用权切换给AWT-EventQuecue线程(其他线程将被中断执行),让其去执行处理事件的方法。
11、用户可以使用javax.swing.Timer(int a, Object b)方法创建计时器对象。其中a表示计时器每隔a毫秒便会“振铃”一次即触发一次actionEvent动作事件,b表示计时器对象注册绑定的监视器对象(注:监视器对象必须是组件类如JFrame、JButton等的子类的实例,否则计时器无法启动)用来处理动作事件。计时器对象调用setReapeats(Boolean b)方法并将参数设置为false后可以将计时器只振铃一次。setInitalDelay(int depay)设置计时器首次触发动作事件的延时,否则延时为a。
12、守护线程:只要其他所有的用户线程(非守护)都执行完毕结束运行后,不管守护线程中的run()方法任务是否执行完毕都会立刻结束运行,简记:”你们(用户线程)都不活了,我(守护线程)也不活了!”。一个线程只有必须在开启之前使用setDaemon(true)方法设置自身是否为守护线程。默认所有的线程都是非守护线程。
@声明:“山月润无声”博主知识水平有限,以上文章如有不妥之处,欢迎广大IT爱好者指正,小弟定当虚心受教!