1. 本周学习总结
1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容。
答:
异常的概念上周的思维导图大致体现,这周就归纳一下错误调试
由于多线程的内容比较散,我就直接用文字总结
-
进程与线程
- 进程是指运行中的应用程序,每一个进程都有自己独立的内存空间
- 线程是指进程中的一个执行流程
- 线程不是程序,必须在程序对应的进程中运行
- 一个进程可以由多个线程组成(在一个进程中可以同时运行多个不同的线程,分别执行不同的任务)
- 并发运行是指进程内的多个线程同时运行(例如:QQ可以同时接收消息、发送消息、传送文件、界面绘制等)
- 创建线程:生成一个Thread类的对象之后,产生一个线程
- ×方法一:定义一个Thread类的子类,覆盖Thread类的run()方法,然后创建该子类的实例
- ★方法二:定义一个实现Runnable接口的类,实现它的run()方法,然后将这个类的实例作为Thread的构造方法的参数,创建Thread类的实例
- t1.start();//启动了线程
- t1.run();//run方法并没有启动线程,只是在主线程中调用了 t1.run(); 方法
-
Runnable与任务
- Runnable本身不是线程,只有Thread才是线程。必须将实现Runnable的类的对象放入Thread中,才能在线程中运行
Runnable task1 = new MyRunnable();
Thread t1 = new Thread(task1);//创建了一个任务对象task1,然后创建了线程t1,t1的任务就是以线程的方式运行task1
t1.start();
- ` new Thread(new MyRunnable()).start();`
- 生成了一个任务对象(MyRunnable)
- 生成了一个线程对象,并为该线程指派任务
- 启动线程
- 使用Runnable可以将线程和任务这两个不同的概念相分离
- 守护线程(Daemon Thread)
- 如果所有前台线程死亡,守护线程自动结束(例如:word一旦关闭,word的提示,语法检查线程自动关闭)
- 方法:setDaemon(true or false);
Thread类还提供一个isDaemon方法,判断是否为守护线程 - setDaemon(true):使线程成为守护线程(必须在start之前调用)
setDaemon(false):使线程成为一般线程(必须在start之前调用)
- 终止线程
- ×可以通过在其他线程中调用stop()方法来终止线程,也可以由线程自己调用stop()方法,自我终止
- ★如果希望线程正常终止,可采用boolean标志来使线程中的run()方法退出
- 线程调度-让出控制权
- 线程暂停:Thread.sleep()方法
- 线程让步:Thead.yield()方法
- 等待其他线程结束:Thead.join()方法
- 多线程示意图
- 多线程的状态转换过程
2. 书面作业:本次PTA作业题集异常、多线程
finally:题目4-2
1.1 截图你的提交结果(出现学号)
答:截图如下:
1.2 4-2中finally中捕获异常需要注意什么?
答:不管tyr-catch中是否捕获到resource.open(sc.nextLine());
的异常,finally中的代码段是一定会被执行的,根据题目要求大致意思就是不管资源打开是否成功都要对resource.close();
进行try-catch,所以要把对资源关闭的try-catch代码段放在finally的代码段内,如下代码所示:
finally{
try{
resource.close();
System.out.println("resource release success");
}catch(RuntimeException e){
System.out.println(e);
}
拓展:分情况说说try-catch-finally的执行过程:
- 在java 的异常处理中,在抛出异常的情况下,程序执行完 try-catch里面的代码块之后,该方法并不会立即结束,而是继续试图去寻找该方法有没有 finally 的代码块
- 如果没有 finally 代码块,整个方法在执行完 try-catch 代码块后返回相应的值来结束整个方法
- 如果有 finally 代码块,此时程序执行到 try-catch 代码块里的 return 语句之时并不会立即执行 return,而是先去执行 finally 代码块里的代码
- 若 finally 代码块里没有 return 或没有能够终止程序的代码,程序将在执行完 finally 代码块代码之后再返回 try-catch 代码块执行 return 语句来结束整个方法
- 若 finally 代码块里有 return 或含有能够终止程序的代码,方法将在执行完 finally 之后被结束,不再跳回 try 代码块执行 return
用异常改进ArrayIntegerStack:题目4-3
2.1 截图你的提交结果(出现学号)
答:截图如下:
2.2 实验总结
答:4-3主要是对栈满栈空的异常处理,直接用if语句判断栈满或栈空(栈满:top>=capacity;栈空:top=0;),然后根据题目要求throw出FullStackException或EmptyStackException,此外,需要注意的是裁判测试代码中是没有对capacity和arrStack进行初始化定义的,需要我们自己写,但是pta的提交答案是不需要包括进去的,否则会编译错误的;
//初始化
public ArrayIntegerStack(int size){
this.capacity=size;
this.arrStack=new Integer[size];
}
主要代码如下:
自定义异常:题目5-4
4.1 截图你的提交结果(出现学号)
答:截图如下:
4.2 自定义异常有哪几个关键点?
答:
1.定义IllegalScoreException异常类属于checked exception(即希望该异常一定要被捕获处理)->继承自Exception
class IllegalScoreException extends Exception {
public IllegalScoreException(String message){
super(message);
}
}
2.定义IllegalNameException异常类属于unchecked exception->继承自RuntimeException
class IllegalNameException extends RuntimeException {
public IllegalNameException(String a) {
super(a);
}
}
3.自定义的异常在抛出时要明确告诉用户异常的原因:要求异常名要有意义,最好还要输出产生异常的信息,例如:
//由IllegalScoreException及括号内的信息明显看出其表示异常产生的原因:成绩是不符合要求的
if(score<0||score>100)
throw new IllegalScoreException("score out of range, score="+score);
PS:关于5-4还有很重要的一点就是输出格式,空格什么的都要注意,我就是因为多了一个空格导致答案部分正确了好几次。
读取文件并组装对象(实验任务书中中的题目3:读取文件并组装对象)
给出关键代码(需出现你的学号)
答:对Scanner in = new Scanner(new File("身份证号.txt"));
进行FileNotFoundException异常捕获,如果try-catch只包含该代码段,后面的所有信息录入都会出现问题,所以try-catch必须包含整段代码;对于信息不全的问题,在信息录入的时候对其进行判断,如果不符合要求就抛出异常
public class readFile004 {
public static void main(String[] args) throws Exception {
try {
Scanner in = new Scanner(new File("身份证号.txt"));// 为myfile.txt这个File创建一个扫描器in
ArrayList<User> arr=new ArrayList<User>();
while (in.hasNextLine()) {
String line = in.nextLine();// 读出myfile.txt的下一行
Scanner lineScanner = new Scanner(line);// 为每一行建立一个扫描器
// System.out.println("lineScanner="+lineScanner);
lineScanner.useDelimiter(" ");// 使用空格作为分隔符
// System.out.println(line);
try{
String a1 = lineScanner.next();// 姓名
if (a1.isEmpty())
throw new Exception("Name is null");
String a2 = lineScanner.next();// 身份证号
if (a2.isEmpty())
throw new Exception("ID is null");
String a3 = lineScanner.next();// 性别
if (a3.isEmpty())
throw new Exception("Gender is null");
String a4 = lineScanner.next();// 年龄
if (a4.isEmpty())
throw new Exception("Age is null");
String a5 = lineScanner.next();// 地址
if (a5.isEmpty())
throw new Exception("Address is null");
while (lineScanner.hasNext()) {// 谨防地址只有一段
a5 += lineScanner.next();
System.out.println(a1 + a2 + a3 + a4 + a5);
arr.add(new User(a1,a2,a3,a4,a5));
}}catch(Exception e){
System.out.println(e);
continue;
}
}
in.close();
} catch (FileNotFoundException e) {
System.out.println(e);
}
}
}
//排序
Collections.sort(arr, new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
// TODO Auto-generated method stub
if(o1.getAge().compareTo(o2.getAge())>0)
return -1;
return o1.getAge().compareTo(o2.getAge());
}
});
学会使用Eclipse进行调试:观看相关调试视频
5.1 简述使用Eclipse进行调试需要几步?
答:
1.在正确的地方设置断点
2.启动调试模式
3.Eclipse有一个专门的debug perspective(长得像只萤火虫),专门用于调试
4.查看状态值
5.2 调试时F5, F6, F7快键键各有什么不同?什么情况该使用哪个快捷键?
答:
F5:step into
F6:step over,跳过
F7:step return,跳出
F8:resume,恢复运行直到碰到下一个断点
5.3 除了Eclipse的调试器,你还使用什么方法调试程序?
答:使用System.out.println("x="+x);打印出任意变量的值,如果碰上某个变量打印出现异常就能找到出错点
5.3 选做:实验任务书中的题目5:使用Eclipse进行调试中的选做
答:目前停留在调试阶段
登录调试没什么大问题
输入留言出错
题集多线程
6.1 程序填空3-1、3-2。(截图提交结果,出现你的学号)
答:截图如下:
6.2 函数4-1(Thread)、4-2(Runnable)(截图提交结果,出现你的学号)
答:截图如下:
函数4-1(Thread)
4-2(Runnable)
6.3 函数4-3(Runnable与匿名内部类)(截图提交结果,出现你的学号),并使用Labmda表达式改写。
答:截图如下:
lambda表达式改写如下:
Runnable r=()->{
System.out.println(mainThreadName);
System.out.println(Thread.currentThread().getName());
//System.out.println(Arrays.toString(getClass().getInterfaces()));//getClass()会报错
System.out.println(Arrays.toString(Thread.class.getInterfaces()));//修改过后
};
Thread t1 =new Thread(r);
getClass()会报错
改写成功
6.4 实验总结
答:
- 3-1考察守护线程
setDaemon(true)
的用法,主线程退出时,在main方法中所启动的线程也要自动结束即将线程t1设为守护线程,必须在start之前调用 - 3-2考察join()方法,等其他线程执行完再执行本线程;线程打印完后,才执行主线程main方法的最后一句即采用
t1.join();
先执行t1,等t1结束后再执行main的最后一句。 - 4-1考察Thread类的创建,因为继承自Thread,所以run方法编写时要
super.run();
根据裁判测试程序可以知道MyThread是带参的,所以在MyThread类中要写出如下代码:
private int n;
public MyThread(int n) {
// TODO Auto-generated constructor stub
this.n=n;
}
- 4-2题目要求每个传入的word只能检查一遍,所以就将检查过的word置为空,并在判断word与alien的时候多加一个判空的条件;在stopMe方法中使用
Thread.yield();
来阻止线程运行 - 4-3要给t1编写一个匿名内部类使它能够完成三个输出任务,将三个输出写进新建的Runnable里,充当t1的匿名内部类即可
源代码阅读:多线程程序BounceThread
7.1 哪个类是支持多线程的类,它实现了什么接口。这个类做了些什么?
答:根据class BallRunnable implements Runnable
,BallRunnable实现Runnable接口,是支持多线程的类;
让小球沿着运动轨迹走,走过的就sleep停止,继续走下一步,有点类似电影画面一幕一幕地跳过去,播放过的就sleep,继续播放下一个画面
for (int i = 1; i <= STEPS; i++)
{
ball.move(component.getBounds());
component.repaint();
Thread.sleep(DELAY);
}
7.2 Ball.java这个程序只做了两件事,这两件事分别是什么?
答:
1.球移动到下一个位置,如果它击中一个边缘就扭转方向,即使一个球在一个矩形的边缘移动和反弹
Moves the ball to the next position, reversing direction if it hits one of the edges.
2.在当前位置得到球的形状
Gets the shape of the ball at its current position.
7.3 BallComponent也只做了两件事,这两件事分别是什么?
答:
1.画出球的分量
The component that draws the balls.
2.在面板上添加一个球
Add a ball to the panel.
7.4 BounceThread中,什么时候启动了新线程?
答:在加入一个小球之后启动新线程
public void addBall()
{
Ball b = new Ball();
comp.add(b);
Runnable r = new BallRunnable(b, comp);
Thread t = new Thread(r);
t.start();
}
7.5 这个程序是如何实现?一个大致的执行流程是什么?
答:首先创建一个JavaFrame,编写一个Ball类规定小球的位置以及运动轨迹(沿矩形框运动),编写一个BallComponent画球以及添加球;当点击添加按钮后,一个小球进入界面,开始沿固定的轨迹运动,到达指定位置后停止运动,点击一次添加一个小球,做上述运动;点击关闭后,窗体关闭。
购物车系统中的多线程
8.1 购物车系统中可能存在哪些多线程问题?
答:例如淘宝上的一元抢购应该算是多线程吧,一样商品同时被多个用户抢购
3. 码云上代码提交记录
题目集:异常、多线程(3-1, 3-2, 4-1, 4-2, 4-3)
3.1. 码云代码提交记录:在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图
答:码云截图如下