异常概述
什么是异常?
异常就是程序出现了不正常的情况。
程序在执行过程中,出现的非正常的情况,最终会导致 JVM 的非正常停止。
Java有一套独立的异常处理机制,在遇到异常时,程序会抛出一个封装了错误信息的异常对象。
异常分类
编译时异常
直接继承Exception,也叫检查时异常。
在编译时期就必须处理,否则编译失败,程序无法运行。
(如日期格式化异常ParseException)
运行时异常:
继承自RuntimeException的异常。
编译期间无需处理,可以通过优化代码逻辑来解决。
(如空指针异常,数组索引越界异常,类型转换异常等)
异常的处理
JVM 的默认处理方案
如果程序出现了问题,我们没有做任何处理,最终 JVM 会做默认的处理。
程序停止执行。
把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
异常处理 — try…catch捕捉异常
如果程序出现异常而不处理,最终异常会传递到JVM虚拟机进行默认的处理,此时程序会终止执行。
为了提高程序的健壮性,通常需要对异常进行捕捉和处理。格式如下:
执行流程:
1、一旦出现异常,try{}里面的代码将停止执行,跳转到对应的catch{}块里的代码继续执行。
2、catch执行结束后,会继续往下执行catch后面的代码。
好处:可以让程序继续往下执行。
try…catch使用注意
如果try中没有遇到问题,怎么执行?
正常执行try里面的代码,但是不会执行catch里面的代码。
如果try中遇到了问题,那么try下面的代码还会执行吗?
在try中一旦遇到问题,会马上中断try语句块的代码,会直接跳到相应的catch结构中执行。
如果出现的问题没有被捕获,那么程序如何运行?
没有被捕获的异常会直接抛给上层调用者,如果都没捕捉处理,最终会传给虚拟机,导致程序运行停止。
try…catch使用注意
同时有可能出现多个异常怎么处理?
多个catch使用注意:
1.多个catch中的异常不能相同。
2.若catch中的多个异常之间有子父类异常的关系,那么子类异常要在上面的catch处理,父类异常在下面的catch处理。
3.如果出现异常,多个catch最多也只会执行一个。(从上往下匹配)
查看异常信息
finally代码块
因为异常会引发程序跳转,导致某些语句执行不到,而有一些特定的代码无论异常是否发生都需要执行。
finally代码块就可以解决这个问题,在finally代码块中的代码一定会被执行。
说明:
•不管是否发生异常,finally代码块都会被执行。
•因此可以在finally代码块中执行关闭连接、关闭文件和释放线程锁的操作。
异常处理 — throws声明异常
当一个方法内部产生异常,而方法无法做出处理时,可以在该方法的头部声明这个异常,把异常交给调用者进行处理。(相当于上报异常,做免责声明)
throws的使用场景:
throws 声明抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由上一级调用者处理,如果调用者也不知道如何处理,那就继续向上声明抛出异常,以此类推直到main方法。
如果 main 方法也不知道如何处理这种类型的异常,也可以使用 throws 声明抛出异常,该异常将交给 JVM 进行默认处理。
方法重写时的注意:
1.当进行方法重写时,子类重写的方法throws的异常的范围不能大于父类方法的异常范围。
2.父类方法没有声明抛出编译时异常,子类重写的方法也不能抛出编译时异常。
3.建议重写的方法声明的异常和父类方法保持相同即可。
小结
两种处理异常方式的小结
声明 throws
①对可能出现异常的方法进行异常声明。
②告知调用者某个方法可能有问题,方法自身没有进行处理,而是让调用者去处理。
捕获 try…catch
throw关键字
throw产生异常
Java中提供了throw关键字,可以在程序运行过程中,抛出某种特定的异常。
注意:throw异常以后,后面的代码将停止执行。
产生异常的意义
①在方法中,当传递的参数有误,程序没有运行下去的意义时,可以直接抛出异常,结束方法。
②告知调用者方法中出现了问题,让调用者修改代码逻辑。
throws 和 throw 的区别
throws
是异常的处理方式之一,在方法定义时进行声明。
表示声明异常,告知调用者,该方法有可能会出现这样的异常。
throw
是产生一个异常的关键字,用在方法体内部。
表示创建并抛出一个异常对象,throw与return有一样的效果,执行了throw之后,方法调用会结束。
自定义异常
JDK提供的异常虽然比较多,但是不一定符合我们的需求。
此时我们可以根据自己的业务来定义异常类。例如年龄负数问题,考试成绩负数问题
自定义异常存在的意义:就是为了让控制台的报错信息更加的见名之意。
异常小结
①异常的分类:编译时异常 和 运行时异常
编译时异常:继承自Exception的异常,需要显式处理。
运行时异常:继承自RuntimeException的异常,无需显式处理。
②异常的处理方式:throws和 try-catch
lthrows抛出的意义:让方法停止并告诉调用者这里出现了问题。
ltry-catch捕获的意义:让程序可以继续往下执行。
③异常处理通常都是针对编译时异常,对于运行时异常,需要强化代码逻辑避免发生。
●
④自定义异常的意义:让程序的提示报错更加的见名知意。
●
⑤产生异常对象:thrownew 异常类构造器();
多线程概述
并发和并行
l并行:在同一时刻,有多个指令在多个CPU上同时执行。
l并发:在同一时刻,有多个指令在单个CPU上交替执行。
进程
进程指在内存中运行的应用程序。
每个进程都有自己独立的一块内存空间,在Windows系统中,一个运行的应用程序就是一个进程。
查看任务管理器,可以看到系统正在运行着的进程。
线程
线程是进程的执行单元,是CPU调度的最小单位。
一个进程可以由多个线程组成,线程间共享进程的所有资源。
一个进程如果有多个线程在执行,则称为多线程程序。
概述小结
并发和并行
l并行:在同一时刻,有多个指令在多个CPU上同时执行。
并发:在同一时刻,有多个指令在单个CPU上交替执行
进程和线程
l进程:就是操作系统中正在运行的一个应用程序。
线程:就是应用程序中做的事情。比如:360软件中的杀毒,扫描木马,清理垃圾。
多线程并发原理
l计算机中的CPU,在任意时刻只能执行一条机器指令。
l每个线程只有获得CPU的使用权才能执行代码。
线程调度方式:
分时调度
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
抢占式调度
优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择 一个线程执行,Java使用的是抢占式调度。
多线程的实现方式
实现多线程的3种方式:
①继承Thread类的方式。
②实现Runnable接口的方式。
③使用线程池的方式。
方式1:继承Thread类
步骤:
1.自定义一个线程类继承Thread类。
2.重写run()方法。
3.创建自定义线程类的对象。
4.调用start方法,启动线程。
面试小问题
l为什么要重写run()方法?
因为run()中的代码就是线程要执行的任务。
lrun()方法和start()方法的区别?
run():封装线程要执行的任务代码,当线程启动后,会被自动调用运行。
start():启动线程,然后由JVM调用此线程的run()方法。
方式2:实现Runnable接口
步骤:
1.自定义类实现Runnable接口。(任务类)
2.重写接口的run()方法。
3.创建任务类的对象。
4.创建Thread类的对象,把任务对象作为构造方法的参数。
5.调用start方法,启动线程。
线程常用的方法
线程优先级:
线程优先级从低到高分别有1~10级,通常CPU会优先执行优先级较高的线程任务。
但这也不是绝对的,因为线程执行还是有随机性,只是概率上来说优先级越高的线程越有机会先执行。
线程同步机制
当多个线程访问共享数据,且多个线程对共享数据有更新操作时,就容易出现线程安全问题。
Java中提供了同步机制来解决线程安全问题。实现方式有三种:
l同步代码块
l同步方法
lLock锁机制
同步代码块
l格式:
synchronized(同步锁) {
有线程安全问题的代码
}
l原理:
在多线程环境下,多个线程会抢占同步代码块中的锁对象。当一个线程获取锁,就可以成功进入同步代码块,其他线程获取不到锁,需要在同步代码块外面等待(阻塞)。
获得锁的线程执行完同步代码块后就会释放锁,此时所有等待的线程会重新争夺锁对象(释放锁的线程也会再次参与争夺)。抢到锁的线程就可以进入同步代码块执行。
同步锁特点:
1.任何对象都可作为同步锁使用。
2.多个线程会对锁对象进行抢夺,所以需要保证多个线程操作的是同一把锁。(锁对象需要唯一)
同步方法
同步方法中的锁:
l实例方法(无static修饰):同步锁对象就是this。(当前方法调用者对象)
l静态方法(static修饰):同步锁对象为当前类的Class对象。
(类名.class 或者 对象名.getClass() 可以获取类的字节码对象 )
同步代码块和同步方法区别
l同步方法是锁住方法中所有代码;同步代码块可以锁定指定代码,锁的控制粒度更细。
l同步方法不能指定锁对象,同步代码块可以指定锁对象。
Lock锁
JDK1.5开始,并发包(java.util.concurrent)中新增了Lock接口和相关实现类来实现锁的功能,它提供了与synchronized关键字类似的同步功能。Lock中提供了获得锁和释放锁的方法:
lvoid lock():获得锁
lvoid unlock():释放锁
l
Lock接口的常用实现类为 ReentrantLock,推荐格式如下: