本帖最后由 小石姐姐 于 2018-1-5 09:29 编辑
javaEE第二阶段 - 异常、多线程笔记节选
Exception 异常
异常
* 概述
* 写代码时出现的编译或运行时的异常
* 异常包含了错误的类型、原因及位置
* 体系结构
* Throwable(最顶层)
* Error:出现的不能够处理的严重问题
* Exception:可以处理的问题 -- 编译时异常
* RuntimeException -- 运行时异常
* 常见异常:
* `NullPointerException`
* `ArrayIndexOutOfBoundException`
* 任何数字/10都会抛出异常
异常处理
* jvm处理的方式
* 如果异常我们没有处理,jvm会帮我们处理,他会把异常类型,原因和位置显示在命令行
* 手动异常处理方式
* **try...catch语句**
* try{
* 有可能出现问题的代码;
}catch(异常对象){
处理异常;
}
```
try...catch语句的执行顺序
首先执行try语句
异常下面的代码不执行,直接跳入catch语句中,catch语句结束后,try...catch结束
```
* 异常的处理方式: 在方法声明上抛出
* 声明方法会抛出异常
* 使用`throws`关键字(记住这个带s)
* 定义位置: 方法形参后, 如果抛出多个异常, 可以用`,`逗号分隔
* 作用: 不捕获异常, 当发生异常时向方法外界抛出, 直到最顶层的方法, 最终终止程序
* 使用场景: 一般在该方法不能处理异常, 或希望外界处理异常时使用
* 注意:
* 定义在方法上的抛出异常属于**编译时异常**, 编写代码调用该方法时IDE会提示去处理异常
* 抛出异常的定义格式
* 多异常处理
* 多异常的捕获:
* 可以写多个catch代码块来分别处理同一个try代码块中的多个异常
* 可以使用多个try...catch语句
* 使用一个try和多个catch
* 多个catch之间的顺序,可以有子父类关系,如果被捕获的异常类没有继承关系, 则catch的顺序可以随意定义
* 平级之间没有顺序
* 如果有子父类,父类异常必须放在后面
* 多个catch代码块的执行逻辑
* try代码块中抛出的异常, 如果catch中有对应的具体异常, 则执行对应的catch代码块. 其他catch代码块不会执行(类似于if...else if, switch...case)
* try代码块中抛出的异常, 如果catch中没有对应的具体异常, 则所有catch代码块都不会执行. 相当于异常没有捕获, 仍然会导致程序终止
Throwable常用方法
* Throwable
* String getMessage() --- 原因 - 异常的信息. 没有原因返回null
* String toString() --- 类型+原因 - 异常的类型和原因
* void printStackTrace() --- 类型+原因和位置 - 使用标准错误输出流打印异常信息
*
##### finally
* finally - 组合try...语句
* 格式
```
try{
有可能出现问题的代码;
}catch(异常对象){
处理异常;
}finally{
释放资源;
清理垃圾
}
```
异常的分类
* 运行时期的异常
* RuntimeException的子类就是运行时期的异常,在编译时起,可选择处理
* 编译时期的异常
* 是Exception的子类,非RuntimeException子类
* 编译时必须处理
* 抛出
* try...catch
```
throws:处理异常的方式,把异常抛出
throw:制造异常
```
**注意** 如果抛出编译时期异常,必须抛出异常
如何定义一个异常类
* 自定义异常
* 自定义编译时异常类:
* 定义一个类, 继承`Exception`或其子类(非RuntimeException), 重写构造方法
* 自定义运行时异常类:
* 定义一个类, 继承`RuntimeException`或其子类, 重写构造方法
* 使用自定义异常的方式:
* 使用编译时异常:
* 在方法声明上, 使用`throws`抛出`Exception`或其子类的类型
* 使用运行时异常:
* 在方法内部的代码中, 使用`throw`(注意没有s)抛出`RuntimeException`或其子类的**对象**
* throws和throw的区别:
* `throws`: 用于抛出编译时异常, 在方法声明上使用
* `throw`: 用于主动抛出运行时异常, 在方法中使用
多线程
线程与进程
* 进程 - Process
* 当前正在运行的程序,一个应用程序在内存中的执行区域
* 线程 - Thread
* 线程依赖于进程
* 是进程中的一个执行控制单元,执行路径
* 一个进程可以有多个线程,也可以有多个线程
##### 多线程和多线程特点
* 单线程
* 安全性高,效率低。
* 多线程
* 安全性低,效率高。
多线程的实现方式
* Thread
* 方法
* String getName() - 返回该线程的明知
* void SetName(String name) - 改变线程的明知
```
CPU执行程序是随机的
```
* 第一种方法
* 是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。
* 第二种方法
* 是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动
创建线程的第一种方式: 继承Thread类
* `java.lang.Thread`类: 实现了`Runnable`接口
* 构造方法
* `Thread Thread()`: 创建Thead对象
* `Thread Thread(Runnable r)`: 通过Runnable对象创建Thread对象
* `Thread Thread(Runnable r, String threadName)`: 通过Runnable对象创建Thread对象并指定线程名
* 成员方法
* `void start()`: 启动线程, 即让线程开始执行`run()`方法中的代码
* `String getName()`: 获取线程的名称
* `void setName(String name)`: 设置线程名称
* 静态方法
* `static Thread currentThread()`: 返回对当前正在执行的线程对象的引用
* `static void sleep(long millis)`: 让所在线程睡眠指定的毫秒
main-主方法是单线程
* `main()`方法
* 也是执行在一个线程中的, 该线程的名称为`main`, 一般称为主线程, 主线程和其他线程没什么区别
* 所以main()方法是单线程的, 方法中的代码是一行一行向下执行的
创建线程的第二种方式: 实现Runnable接口
* `java.lang.Runnable`接口: 可将其对象看作是子线程要运行的任务
* 抽象方法:
* `void run()`
* `Runnable`接口出现的原因
* 因为Java只支持单继承, 如果继承了`Thread`类, 就无法继承其他类, 局限性太大, 所以使用实现`Runnable`接口的方式, 既能继承其他类, 还能实现多个接口, 不会影响类的扩展性
多线程中的线程安全问题: 使用同步代码块解决共享资源的问题
* 同步:
* 表示多个线程在执行同步的代码时, 这些线程只能按顺序一个一个去执行
* 优缺点
* 同步安全性高, 效率低
* 不同步安全性低, 效率高
* 使用`synchronized`关键字:
* 同步代码块: 使用`synchronized`修饰的代码块
* 作用:
* 被同步代码块包裹的代码相当于在一个房间内, 锁对象相当于房间的锁
* 一个线程进入同步代码块, 会把门锁上, 同步代码块外面的线程看到同步代码块内部有线程, 只能在外面等待
* 直到同步代码块内部的线程执行完毕从代码块中出来, 释放了锁, 外面等待的线程才能随机进去一个
* 应用位置:
* 哪些代码属于共享操作, 需要避免安全问题, 就将这些代码放入同步代码块
* 术语
* 线程进入同步代码块, 叫`获取锁`
* 线程出同步代码块, 叫`释放锁`
* 同步方法: 使用`synchronized`修饰的方法(下面讲)
* 锁对象
* 锁是一个**任意类型**的对象
* Object对象可以, String对象可以, Student对象等也可以...
* 锁对象**必须是被所有线程共享的**, 也就是说多个线程都共用一个锁
* 如使用同一个Runnable对象中的成员变量
* 或使用某个类的静态变量
* 或使用某个类的字节码对象
* 同步必须配合锁对象来使用
```java
// 同步代码块格式
synchronized (锁对象) {
// 要同步执行的代码
}
```
* **出现多线程的安全问题, 检查一下2个方面**
1. 对于操作了了共享数据的代码是否是同步的?
2. 同步使用的是否是同一个锁对象?
多线程中的线程安全问题: 使用同步方法解决
* 同步方法:
* `synchronized`修饰的方法
* 作用:
* 该方法在同一时间只能被一个线程执行, 多个线程需要按顺序一个一个调用方法
* 同步方法的锁对象:
* 同步方法也有锁对象
* 静态同步方法:
* 是方法所在类的`Class`对象, 也就是该类的字节码对象
* 非静态同步方法:
* 是`this`, 也就是该方法所在类的对象
|
|