Java高级学习-异常和线程

举报
AAAI 发表于 2021/04/02 04:03:13 2021/04/02
【摘要】 异常 异常的超类java.lang.Throwable Throwable:包括Error和Exception Exception:编译期异常,包括:RuntimeException:运行期异常 异常产生过程 JVM检测程序出现异常: JVM会根据异常产生的原因创建一个异常对象,这个异常对象包括异常产生的(内容,原因,位置);在getElement方法中,没...

异常

异常的超类java.lang.Throwable

Throwable:包括Error和Exception

Exception:编译期异常,包括:RuntimeException:运行期异常

异常产生过程

JVM检测程序出现异常:

  • JVM会根据异常产生的原因创建一个异常对象,这个异常对象包括异常产生的(内容,原因,位置);
  • 在getElement方法中,没有异常处理逻辑{ try…catch},那么JVM会把异常对象抛给方法的调用者main方法来处理这个异常;
  • main方法里也没有异常逻辑,继续把对象抛出给main方法的调用者JVM;
  • JVM接收到异常对象,先进行打印异常对象,再终止正在执行的java程序–>中断处理

异常的处理

throw

使用throw关键字在指定的方法中抛出指定的异常

使用格式:throw new xxxException(“异常产生原因”);

注意:

  • 1.throw关键字必须写在方法内部
  • 2.throw关键字后面的new的对象必须是Exception或者Exception子类对象
  • 3.throw关键字抛出指定的异常,必须处理这个异常对象(编译期异常必须处理:throws/try…catch),但是throw关键字后面创建的RuntimeException或者RuntimeException的子类对象,可以不处理,交给JVM进行处理

获取数组指定索引处问题:必须校验传递的参数(数组)的合法性:

  • 数组为空:空指针异常(NullPointerException) 运行期异常
  • 数组索引不存在:数组索引越界异常(ArrayIndexOutOfBoundsException) 运行期异常
  • 集合越界:IndexOutOfBoundsException
  • ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException
Objects非空判断

Objects由一些静态方法组成,容忍null-save(空指针安全)或null-tolerant(容忍空指针)

public static T requireNonNull(T obj) :查看指定引用对象不是null

空指针异常:throw new NullPointerException(“xxx”)

调用方法:Objects.requireNonNull(obj);

重载:Objects.requireNonNull(obj, “xxx”); //抛出xxx

throws

异常处理的第一种方式,交给别人处理,异常后面的代码不执行

作用:

当方法内部抛出异常对象时,我们必须处理这个异常对象

使用throws关键字处理异常对象,会将异常对象声明抛出给方法的调用者,最终交给JVM处理–>中断处理

修饰符 返回值类型 方法名( 参数列表 ) throws AAAException, BBBException{

throw new AAAException(“XXX”); throw new BBBException(“XXX”); }

注意:

  • throws关键字必须再在方法声明处
  • throws关键字后面声明的异常必须是Exception或者Exception的子类
  • 方法内部有几个异常对象,那么throws后面必须也声明几个异常,如果抛出的多个异常有子父类关系,直接声明父类异常就可以
  • 调用了一个声明保存异常的方法,就必须处理声明的异常:继续throws抛出 /try…catch,让方法的调用者处理,使用try…catch,throw 的XXX不打印。直接打印catch里面的内容

FileNotFoundExcption(文件路径不对)是编译异常,抛出编译异常,就必须处理这个异常:throws

IOException(文件后缀名不对)

FileNotFoundExcption extends IOException 只声明IOException就行

throw抛出编译异常,throws进行处理异常

捕获异常try…catch

try{
可能产生异常的代码
}catch(定义一个异常遍历,用来接受try抛出的异常对象){
异常处理逻辑 + 记录到日志中 }

  
 
  • 1
  • 2
  • 3
  • 4

注意:

  • ​ try多个异常,则使用多个catch
  • ​ 处理完catch,继续执行try…catch后面的代码,同时try在异常后面的代码不执行

Throwable类的方法

getMessage() : 返回此throwable的描述

toString():返回此throwable的详细消息字符串

printStacKTrace() JVM打印异常对象,默认

try{
可能产生异常的代码
}catch(IOException e){
sout(e.getMessage())
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

finally

必须与try一起使用,一般用于资源释放(回收),无论程序是否出现异常,都要进行资源释放(IO)

异常注意

多个异常进行处理

  1. 多个异常分别处理 多次try…catch

  2. 异常多个处理 try…catch…catch…catch

​ catch定义的异常变量,如果有子父类,子类异常变量必须写在父类上面。因为try如果出现异常对象,会把异常对象抛给catch处理,异常对象会从上到下异常赋值给catch中的异常变量。可能会使用多态进行子类转换为父类。

  1. 多个异常一次捕获一次处理 使用(Exception e )进行处理—超类

运行时异常可以不进行处理不捕获

finally有return,则会永远防护finally的结果,要避免这种情况。

父类抛出多个异常,子类重写父类方法时应该也抛出和符类相同的异常或者父类异常的子类或者不抛出

父类没有抛出异常,子类重写父类方法时也不能抛出异常,只能捕获

自定义异常

格式:

public class xxxException extends Exception | RuntimeException {

添加一个空参数的构造方法;添加一个带异常信息的构造方法(方法内部调用父类带异常信息的构造方法,让父类进行处理异常信息); }

继承RuntimeException 运行期异常,无需处理,交给JVM中断处理

继承Exception 编译期异常,就要throws / try…catch

多线程

并发:多个事件在同一个时间段内发生。交替执行。

并行:多个事件在同一个时时刻内发生。同时执行。

进程:一个内存中运行的应用程序,每一个进程都要独立的内存空间,一个应用程序可以同时运行多个进程,进程是系统运行程序的基本单位。

线程:是进程的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,可以有多个线程–多线程程序。多个线程互不影响

线程调度

分时调度:多个线程轮流使用CPU的使用权,评价分配占用CPU的时间

抢占式调度:优先让优先级高的线程使用CPU,优先级相同,随机选择一个线程,java的使用为抢占式调度。

创建主线程MainThread

java是单线程,main函数从上到下执行

Thread类的子类

java.lang.Thread类,描述线程的类,多线程程序要继承 extends Thread

第一种创建线程方式步骤

  1. 创建Thread类的子类
  2. 重写Thread类的run方法,设置线程任务
  3. 创建Thread类的子类对象
  4. 调用Thread类的方法start方法,开始新的线程,java虚拟机调用该线程的run方法。结果是两个线程:main线程和新线程(子类对象名.start(),执行run)

内存:会开辟新的栈空间进行执行run方法

获取线程名称:String getName( ) 主线程:main 线程一:Thread-0

获取线程:static Thread currentThread( ) 返回当前正在执行的线程对象的引用

Thread t = Thread.currentThread( ); – Thread[Thread-0, 5, main]

链式编程:Thread.currentThread( ). getName( )

设置线程名称:setName( String name) / Thread( String name)带参数的构造方法。传递参数名称–线程名称,父类给子线程类进行起名,super(name)

sleep

public static void sleep ( long millis ) : 以毫秒数暂停

第二种创建线程方式

实现Runnable接口 implements Runnable ,java.lang.Runnable

Runnable接口应该由那些打算通过某一线程执行其实例的类来实现。类需要定义一个run的无参数方法。

Thread(Runnable target),分配新的Thread对象

Thread(Runnable target, String name)

步骤

  1. 实现Runnable接口的实现类 implements Runnable

  2. 实现类进行重写Runnable接口的run方法,设置线程任务

  3. 创建Runnable接口的实现类对象

    Runnable run = new RunnableImpl( ) ; //多态也可以

  4. 创建Thread类对象,在构造方法中传递Runnable接口的实现类对象

    Thread t = new Thread( run ); //因为是lang类,不用导包

  5. 调用Thread类中的start迭代,开启新的线程执行run方法 t.start( );

实现Runnable和继承Thread区别

实现Runnable接口,避免了单继承的局限性,因为一个类只能继承一个类。

实现Runnable接口,增强程序扩展性,降低程序耦合性(解耦)。将设置线程任务和开启新线程进行了分离。在实现类中重写run方法进行设置线程任务,创建Thread类对象,调用start方法,开启新线程。

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享

匿名内部类创建线程

匿名内部类:将子类继承父类,重写父类方法,合为一步。把实现类实现类接口,重写接口的方法,创建实现类对象合为一步。

new 父类/接口 ( ) { 重写父类/接口中的方法 }

继承:new Thread( ) { @Override pubilc void run() { } }.start( );

接口1:Runable r = new Runable( ) { @Override pubilc void run() { } };

new Thread( r ).start( );

接口2:new Thread( new Runable( ) { @Override pubilc void run() { } } ).start( );

线程+同步

线程安全

共享数据时会出现线程冲突,执行语句时会失去CPU的使用权,包括if,计数等操作语句。

同步操作

解决线程安全问题

同步代码块

只让一个线程在同步代码块中执行,效率变低

synchronized(锁对象) { 可能会出现的线程安全问题的代码(访问了共享数据的代码) }

注意:

通过代码块中的锁对象,可以使用任意的对象;

Object  obj  =  new Object();  
new Thread(){ @Override
 public void run() { try...catch synchronized( obj ) {  try...catch /  "XXX" } }  
} .start();

   
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

必须保证多个线程使用的锁对象是同一个。

同步方法

把访问共享数据的代码抽取出来,放到一个方法中,在方法上添加synchronized修饰符

修饰符 synchronized 返回值类型 方法名( 参数列表 ) { }

同步方法的锁对象是实现类对象,就是this

静态同步方法

静态同步方法的锁对象是本类的class属性—>class文件对象( 反射 ),因为静态方法优于对象,创建对象之后才有this。

Lock锁

java.util.concurrent.Locks.Lock接口

Lock接口方法:void lock( ) 获取锁;void unlock( ) 释放锁

Lock接口实现类:ReentrantLock

java.util.concurrent.Locks.ReentrantLock implements Lock

步骤:在成员位置创建一个ReentrantLock对象

Lock l = new ReentrantLock( );

l.lock( ) ; 获取锁 finally{ l.unlock( ) ; }

线程状态

java.lang.Thread.State

  • 新建状态 new Thread( )
  • 阻塞状态:BLOCKED,CPU空闲执行
  • 运行状态:RUNNABLE
  • 休眠状态:TIMED_WAITING,计时等待,CPU空闲也不执行
  • 死亡状态:TERMINATED
  • 无限等待:WAITING

在这里插入图片描述

无限等待:WAITING

调用Object.wait( ) 方法,无限等待 <通信> 调用Object.notify( ) [ Object.notifyAll( ) ]方法,结束等待,唤醒

wait( long m ) : wait方法在毫秒值结束之后还没有醒过来,则自动醒来。

作业

throw与throws的区别

throw关键字通常用在方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即停止,它后面的语句都不执行。

throws关键字通常被应用在声明方法时,用来指定可能抛出的异常。多个异常可以使用逗号隔开。当在主函数中调用该方法时,如果发生异常,就会将异常对象抛给方法调用处。

异常

**NullPointerException:**空指针异常。

​ 当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度等等。

**ArrayIndexOutOfBoundsException:**数组索引越界异常。

当对数组的索引值为负数或大于等于数组大小时抛出此异常。

**ArithmeticException:**算术运算异常。

​ 程序中出现了除以零这样的运算就会出这样的异常,对这种异常,大家就要好好检查一下自己程序中涉及到数学运算的地方,公式是不是有不妥了。

**NumberFormatException:**数字格式异常。

​ 当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常

实现Runnable接口比继承Thread类所具有的优势:

  1. 适合多个相同的程序代码的线程去共享同一个资源。

  2. 可以避免java中的单继承的局限性。

  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和数据独立。

  4. 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类。

文章来源: blog.csdn.net,作者:αβγθ,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_38022166/article/details/115382009

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。