第一章 异常
概念:
指的就是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止
异常体系:
java.lang.throwable : 异常的顶级
子类:
1.Exception 表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,
必须要处理的.
2.Error 严重那个错误Error,无法通过处理的错误只能事先避免,
常用方法:
1. public void printStackTrace():打印异常的详细信息
包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用
printStackTrace.
2.public String getMessage(): 获取发生异常的原因
提示给用户的时候,就提示错误原因,
3.public String toString(); 获取异常的类型和异常描述信息(不用)
分类:
1. 编译时期异常: checked异常,在编译时期,就会检查,如果没有处理异常,则编译失败(如
日期格式化异常)
举例:ArrayIndexOutOfBoundsException
NullPointerException
ClassCastException
IndexOutOfBoundsException
ConcurrenModificationException
2. 运行时期异常: runtime异常,在运行时期,检查异常,在编译时期,运行异常不会编译器检
测 (不报错).(如数学异常)
举例: FileNotFoundException
IoException
ParseException
异常的产生过程解析
工具类:
[Java] 纯文本查看 复制代码
public class ArrayTools{
public static int getElement(int[] arr, int index) {
int element = arr[index];
return element;
}
}测试类:
[Java] 纯文本查看 复制代码
public class ExceptionDemo {
public static void main(String[] args){
int[] arr = ArrayTools.getElement(arr, 4)
System.out.println("num=" + num);
System.out.println("over");
}
}图解:
第二章 异常的处理
关键字: try, catch, finally, throw, throws
throw
用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法执行.
格式:
throw new 异常类名(参数);
throws
概念:
声明异常,将问题标识出来,报告给调用者,如果方法内用过throw抛出了编译时异常,而没有
捕获处理,那么将通过throws进行声明,让调用者去处理,,,,,,用在方法声明之上,用于表示当
前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2...{ }
try....catch
概念: 捕获异常
try:该代码块中编写可能产生异常的代码。
try异常
最后只会抛出一个异常
如果没有捕获到
交给java虚拟机
catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理
在开发中也可以在catch将编译器异常转换成运行期异常处理
如果异常出现的话,会立刻终止程序,如果不想程序终止,所以我们得处理异常:
1. 该方法不处理,而是声明抛出,由该方法的调用者来处理(throws)。
2. 在方法中使用try-catch的语句块来处理异常。
语法格式:
[Java] 纯文本查看 复制代码
try{
编写可能会出现异常的代码
} catch(异常类型 e) {
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
} 异常使用捕获处理的三种方式:
1.多个异常分别处理
2.多个异常一次捕获,多次处理 (常用方式)
3.多个异常一次捕获一次处理
finally 代码块
有一些特定的代码无论异常是否发生,都需要执行,finally代码块中存放的代码都是一定会被
执行. ......当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会执行,否则
finally永远会执行
异常注意事项:
1.运行时异常被抛出可以不处理,即不捕获也不声明抛出
2.如果父类抛出了多个异常,子类覆盖父类方法时,只能抛出相同的异常或者是他的子集
3.父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常,此时子类产生该异常,
只能捕获处理,不能声明抛出
4.当多异常处理时,捕获处理,前边的类不能是后边类的父类
5.在try/catch后可以追加finally代码块,其中的代码一定会被执行,通常用于资源回收
6.如果finally有return语句,永远返回finally中的结果,避免该情况
第三章 自定义异常类
定义:
1.自定义一个编译器异常:自定义类 并继承于java.lang.Exception
2.自定义一个运行时期的异常,:自定义类并继承于java.lang..RuntimeException.
处理自定义异常类:
throws 自定义异常类类名
try catch(自定义异常类类名 变量)
第四章 多线程
并发:
(交替执行)指两个或多个事件在"同一时间段内"发生
并行:
(同时执行) 指两个或多个事件在"同一时刻"发生(同时发生)
进程:
内存中运行的一个应用程序.
每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程.
进程也是程序的一次执行过程,是系统运行程序的基本单位
系统运行一个程序即是一个进程从创建,运行到消亡的过程.
线程:
是进程内的一个独立执行单元(一条代码执行路径)
一个程序运行后至少有一个进程,一个进程中可以包含多个进程
多线程的好处:
效率高
多个线程之间互不影响
线程的调度:
多个线程要并发执行,那个线程被执行,那个线程不被执行,就是调度.
方式:
1.分时调度:所有线程轮流使用CPU,平分占用CPU的时间
2.抢占式调度:优先让优先级高的线程使用CPU;如果优先级相同,则随机选择一个
线程执行.
Java使用的是"抢占式"调度.
主线程:
我们以前写的代码,也在一条线程中执行,该线程叫做"main线程",也成为"主线程.
如果没有额外创建线程,那么程序就只有一个线程,即主线程,此时程序是"单线程"
的单线程的执行特点;
同一个线程内的代码,从上往下一次执行.
创建多线程程序的第一种方式: 继承Thread类
实现多线程的第一种方式:
1.定义类,继承Thread类
2.重写run()方法,run方法内部是线程要执行的任务
3.创建Thread子类的对象,调用start()方法启动线程
java.lang.Thread类 : 表示线程,事项了Rannable接口
void start():启动线程,即让线程开始执行run()方法中的代码
注意:
必须调用start() 方法来开启线程,不能直接调用run() 方法,调用run()会变成
单线程同一线程对象,不能多次调用start()方法
Java是抢占式调度,不同线程的代码,执行顺序是随机的
第六天 线程、同步
第一章 线程
1、Java线程调度是抢占式的,多个线程互相抢夺CPU的执行权。CPU执行哪个线程是随机的
2、多线程情况下,每个线程都有各自的栈内存。
3、Thread类:表示线程,实现了Runnable接口
常用方法:
构造方法
[Java] 纯文本查看 复制代码
Thread(): 创建Thread对象
Thread(String threadName): 创建Thread对象并指定线程名
Thread(Runnable target): 通过Runnable对象创建Thread对象
Thread(Runnable target, String threadName)
成员方法
[Java] 纯文本查看 复制代码
void run(): 用于子类重写,表示线程执行任务,不能直接调用
void start(): 启动线程,让线程开始执行run()方法中的代码
String getName(): 获取线程的名称
void setName(String name): 设置线程名称
静态方法
[Java] 纯文本查看 复制代码
static Thread currentThread(): 返回对当前正在执行的线程对象的引用
void sleep(long mills): 让所在线程睡眠指定的毫秒
创建线程方式二:实现Runnable接口
定义Runnable接口实现类,重写run方法
创建Runnable实现类对象
创建Thread类对象,在构造方法中传入Runnable实现类对象
通过Thread对象调用start()方法启动线程
Thread和Runnable的区别
实现Runnable的好处:
1、避免单继承的局限性
2、增强了程序的扩展性,降低了程序的耦合性
(线程是Thread,任务是Runnable实现类对象,相当于将线程和任务分离)
匿名内部类方式创建线程
new Thread(new Runnable){
重写run()
}
线程安全问题
发生场景:多个线程操作共享资源
问题发生原因:
JVM是抢占式调度,CPU在每个线程之间切换时随机的,代码执行到什么位置是不确定的。
在操作共享资源时,一个线程还没执行完,另一个线程就来操作,就会出现问题
解决多线程操作共享数据的安全问题
3种方式:同步代码块
同步方法
锁机制
同步代码块:使用synchronized关键字修饰的代码块,并传入一个当作锁的对象格式:
[Java] 纯文本查看 复制代码
synchronized(锁对象) {
//操作共享数据的代码
}
注意:锁对象可以是任意类型的一个对象
锁对象必须是被多个线程共享的唯一对象
锁对象的作用:只让一个线程在同步代码块中执行
同步的原理:
线程进入同步代码块前,会争夺锁对象,只有一个线程会抢到
进入同步代码块的线程,会持有锁对象,并执行代码块中的代码
此时同步代码块外的线程处于阻塞状态,只能等待
同步代码块内的线程执行完代码块,会离开同步代码块,并归还锁对象给同步代码块
此时同步代码块外的其他线程就可以继续争夺锁对象
同步方法:
非静态同步方法:(具有默认锁对象:this)
[Java] 纯文本查看 复制代码
public synchronized void method() {
//可能会产生线程安全问题的代码
}
静态同步方法
[Java] 纯文本查看 复制代码
public static synchronized void method() {
//可能会产生线程安全问题的代码
} 静态同步方法的锁对象:当前类的字节码对象
获取一个类的字节码对象的3种方式:
1、对象.getClass
2、类名.class
3、Class.forName(“类的全路径”)
Lock锁
成员方法:
[Java] 纯文本查看 复制代码
void lock(): 获取锁
void unlock(): 释放锁
[Java] 纯文本查看 复制代码
public class RunnableImpl implements Runnable {
Lock lock = new ReentrantLock();
@override
public void run() {
lock.lock(); //加锁
try{
//操作共享变量的代码
} finally {
lock.unlock(); //在finally中保证释放锁
}
}
}
线程安全和效率的特点
程安全,效率低
线程不安全,效率高
线程的状态
锁对象,也称为“同步锁”,“对象监视器”
Object类中关于线程的方法:
成员方法:
[Java] 纯文本查看 复制代码
void notify(): 随机唤醒在同一个锁对象上的某一个处于等待状态的线程
void notifyAll(): 唤醒所有在同一个锁对象上处于等待状态的线程
void wait(): 让当前线程处于无限等待状态
void wait(long timeout): 让当前线程处于计时等待状态,时间到或被唤醒后结束此状态
void wait(ling timeout, int nanos): 让当前线程处于计时等待状态,时间到或被唤醒后结束此状态
线程的生命周期的6种状态:
1、NEW新建
线程被创建,但没有调用start()启动
2、RUNNABLE可运行
调用start()方法后已启动,但可能正在执行run()方法的代码,也可能正在等待CPU的调度
3、BLOCKED阻塞
线程试图获取锁,但此时锁被其他线程持有
4、WAITING无限等待
通过锁对象调用无参的wait()进入此状态
等待其他线程通过锁对象执行notify()或notifyAll()才能结束这个状态
5、TIMED_WAITINGj计时等待
如通过锁对象调用有参的wait(long millis)或sleep(long millis),则进入此状态
直到时间结束之前被其他线程通过锁对象执行notify()或notifyAll()唤醒,或时间结束自动唤醒
6、TERMINATED终止
run()方法结束(执行结束,或内部出现异常),则进入此状态
Object类成员方法:
[Java] 纯文本查看 复制代码
void notifyAll(): 唤醒所有在同一个锁对象上处于等待状态的线程
void wait(long timeout): 让当前线程处于计时等待状态,时间到或被唤醒后结束此状态