赞
踩
异常概念
异常体系
java.lang.throwable
,其下有两个子类
java.lang.Error
和java.lang.Exception
,平常所说的异常是后者。错误
,只能规避,无法处理,尽量避免;exception
编译期异常,写代码时异常。
Error
:错误,必须修改代码,程序才能运行。throw
关键字
使用throw在指定的方法中抛出指定异常
使用格式:throw new xxxException("异常产生的原因")
throw关键字必须写在方法的内部
throw关键字后new的对象必须是Exception或者Exception的子类对象。
throw关键字抛出指定的异常对象,我们就必须处理这个异常对象。
throw关键字后面创建的是RuntimeException或者它的子类对象可以不处理,交给JVM处理
throw后创建的是编译异常(写代码时的异常),则必须处理这个异常,要么throws,要么try…catch
必须对方法传递到参数进行合法性校验,如果参数不合法,必须告知调用者传递的参数有问题。
对传递参数的合法性判断,判断是否为null,
Objects.requireNonNull(obj,"传递的时空null");
异常处理的第一种方法:交给别人处理。
作用:方法内部抛出异常时,就必须处理这个异常对象。最终交给JVM处理。
使用格式:在方法声明时使用
修饰符 返回值类型 方法名(参数裂变) throws xxxException, xxxException{
throw new XXXException(“产生原因”);
}
throws关键字必须写在主方法声明处,
throws关键字后边声明的异常必须是Exception或者Exception的子类
方法内部抛出多个异常对象,那么throws后边也必须声明多个异常;
方法内部如果抛出了多个异常对象有子父类关系,那么直接声明父类异常即可。
调用了一个声明抛出异常的方法,就必须处理声明的异常。
要么使用throws声明抛出,交给方法调用者,最终交给JVM
要么try…catch自己处理异常
异常处理的第二种方法:自己处理。
try{
可能产生异常的代码;
}catch(xxException e){
异常的处理逻辑;一般工作中会记录到日志中。
}catch(){
…}
try中可能抛出多个异常对象,那么可以使用多个catch来处理这些异常对象。
如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕之后,继续执行catch之后的代码
如果try中没有异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try…catch之后的代码。
throwable
getMessage()
返回此 throwable 的简短描述。toString()
返回此 throwable 的详细消息字符串。printStackTrace()
JVM默认此方法,打印异常信息最全面。try…catch中,try异常后的代码块不执行,catch后的代码执行。
finally
中的代码块无论是否出现异常,一定可以执行
多个异常使用捕获该如何处理?
多个异常分别处理。每个异常一个try…catch
多个异常一次捕获,多次处理。一个try,多个catch.(如果多个异常有子父类关系,catch中子类异常必须写在前面)
多个异常一次捕获一次处理。 一个try…一个catch(一个Exception全部处理)。
运行时异常可以不处理,默认给虚拟机处理。
如果finally中有return语句,永远返回finally中的结果,应避免该情况。
如果父类抛出多个异常,子类重写父类该方法时,抛出 和父类相同的异常 / 父类异常的子类 / 不抛出异常
父类方法没有抛出异常,子类重写父类方法时不可抛出异常。此时子类产生异常,只捕获,不能声明抛出。
【父类异常什么样,子类一场就什么样。】
概述
java提供的异常类不够用,自己自定义一些异常类。
格式:public class xxxException extends Exception / RuntimeExcetion{
添加空参数构造方法;public xxxException(){ }//空参构造
添加带构造信息构造方法;public xxxException(String str){ super(str); }//调用父类方法解决异常
}
注意:1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类。
2.自定义异常类,必须的继承Exception或者RuntimeException
继承exception:那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try...catch
继承RuntimeException:那么自定义的异常类就是一个运行异常。无需处理,交给虚拟机处理。中断处理。
自定义异常练习
要求:模拟注册操作,如果用户名已经存在,则抛出异常并提示:亲,该用户名已存在
分析:
使用数组保存已经注册过用户名(数据库)
使用scanner获取用户输入的注册的用户名(前端,页面)
定义一个方法,对用户输入的注册的用户名进行判断
遍历存储到已经注册过用户名的数组,获取每一个用户名
使用获取到的用户名和用户输入的用户比较
true:用户名已存在,抛出RegisterException异常,告知用户“亲,该用户已经被注册”。
false:继续遍历比较。循环结束,提示 ”恭喜注册成功“。
并发与并行
线程与进程
创建线程类
主线程:执行主(main)方法的线程。
单线程程序:java程序中只有一个线程。执行main方法开始,从上到下依次执行。
多线程创建方式一:创建Thread类的子类
java.lang.Thread类:是描述线程的类,我们想要实现多线程程序,就必须继承Thread类。
实现步骤:
1.创建一个Thread类
2.在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么?)
3.创建Thread类的子类对象
4.调用Thread类中的start方法,开启新的线程,执行run方法
void start() 使该线程开始执行;java虚拟机调用该线程的run方法
结果是两个线程并发的运行;当前线程(从调用返回给start方法)和另一个线程(执行其run方法)。
多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。
多线程原理
Thread类:
Thread类构造方法:
public Thread()
:分配一个新的线程对象。public Thread(String namr)
:分配一个指定名字的线程对象。public Thread(Runnable target)
:分配一个带有指定目标新的线程对象。public Thread(Runnable target, String name)
:分配一个带有指定目标的线程对象并指定名字。Thread常用方法:
public String getName()
:获取当前线程的名字。
获取线程的名称:在run方法中
String getName()
返回该线程的名称。static Thread currentThread()
,使用线程的.getName()
获取线程的名称。设置线程中的名称:
void setName(String name)
设置线程名称。public void start()
:此线程开始执行;Java虚拟机调用用此线程的run方法。
public void run()
:此线程要执行的任务在此处定义代码。
public static void sleep(long milllis)
:使当前正在执行的线程暂停毫秒数值。
可以让主程序暂停执行。“秒表打印”。
public static Thread currenThread()
:返回当前正在执行的线程对象的引用。
多线程创建方式二:
Thread和Runnable的区别:
实现Runnable接口创建多线程的好处
一个类只能继承一个类,不能继承其他类。实现了Runnable接口,还可以继承其他类,实现其他接口。
在增强程序扩展性,降低程序耦合性(解耦)。
实现Runnable接口的方式,把设置线程任务和开启新线程进行分离(解耦)。
实现类中,重写run方法: 就是用来设置线程任务。
创建Thread类对象,调用start方法:开启新线程。
匿名内部类:继承/实现;重写;创建子类;一步完成这三个操作。
格式:
new Thread(){
重写run方法
}.start(); //线程的父类
Runnable r = new Runnable(){
重写run方法
};//实现runnable接口
new Thread(r).start();
线程安全
多线程访问共享数据会发生安全问题。
保证线程安全:一个线程在访问共享数据时,其他线程只能等待。保证:始终只有一个线程在卖票。
线程同步:解决线程安全问题。
同步代码块
synchronize(锁对象){
访问了共享数据的代码/可能出现安全问题的代码
}
注意:通过代码块中的锁对象,可以使用任意的对象。
必须保证多个线程使用的锁对象相同。
锁对象作用:吧代码块锁住,只让一个线程在同步代块中执行。
使用方法:将代码块写进Runnable实现类的run方法中。
同步方法
public synchronized void method(){ 可能会产生安全问题的代码块}
:
使用步骤:
method
方法。同步方法也会把方法内部代码锁住,只让一个线程执行。
同步方法的锁对象就是 this。
【静态同步方法:】
lock机制(用的多)
lock锁java.util.current.locks
Lock接口种两个重要方法:lock
和unlock
改进:将安全问题代码写进try中,将l.unlock()写进finally代码块中,无论是否出现异常都会释放锁。
##4线程状态
线程状态概述
线程状态 | 导致状态发生的条件 |
---|---|
New(新建) | 线程刚被创建,但是并未启动。还没调用start方法。 |
Runnable(可运行) | 线程可以在java虚拟机中运行的状态,可能正在运行自己的代码,也可能没有,取决于操作系统处理器 |
Blocked(锁阻塞) | 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变为Runnable状态。 |
Waiting(无限等待) | 一个线程等待另一个线程执行一个动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法唤醒。 |
Timed Wainting(计时等待) | 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Wainting状态。这一状态将一直保持到超时期满或者收到唤醒通知。带有超时参数的常用方法有Thread.sleep,Object.wait。 |
Teminated(被终止) | run方法正常运行结束而消亡;或者因为没有捕获的异常终止了方法而死亡。 |
等待唤醒案例: 线程之间的通信。
创建第一个线程,调用wait方法 ,进入wainting(无限等待)状态。
创建第二个线程,执行结束后调用notify方法,唤醒第一个线程执行。
void wait()
:其他线程调用notify或notifyAll方法前,导致当前线程等待。
void notify()
:唤醒在此监视器上的等待的单个线程;会继续执行wait方法之后的代码。
Timed Waiting(计时等待)
wait(long m)
方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,进入到Runnable/Blocked状态。notifyAll()
:如果有多个等待线程,唤醒所有的等待线程。BLOCKED(锁阻塞)
Waiting(无限等待)
线程间通信
等待唤醒机制
wait():
notify():唤醒等待时间最久的线程。
notifyAll():唤醒等待线上所有的等待的线程。
唤醒之后也不是立即就可以执行,进入Blocked状态的话还是需要争夺CPU使用权;进入Runnable状态的话就可以执行了。
调用wait与notify方法注意的细节。
A:生产者线程类(包子铺)。
B:消费者线程类(吃货):线程类。
C:包子类:皮,馅,状态。
D:测试线程:创建包子对象;创建包子铺(包子)对象.start;创建吃货(包子)对象.start。
线程池:容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
使用线程池的好处:
java.util.concurrent.Executors
:生产线程池的工厂类。(jdk1.5之后提供的)
static ExecutorService newFixedThreadPool(int nThreads)
:创建一个可重用固定线程数的线程池。
返回值:
java.util.concurrent.ExecutorService
:线程池接口
submit(Runnable task)
:从线程池中获取线程,调用start方法,实行线程任务。提交一个Runnable任务用于执行。void shutdown()
:关闭/销毁线程池。线程池持使用步骤:
Executors
里边提供的静态方法newFixedThreadPool
生产一个之当线程数量的线程池。ExcutorService
中的方法submit
,传递线程任务(实现类),开启线程,执行run方法。面向对象的思想:做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成任务。强调通过对象的形式来做。
函数时编程思想:强调做什么,而不是以什么形式做。只要能获取到结果就行,重视结果,不重视过程。
冗余的Runnable代码
编程思想转换:体验Lambda
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"创建了一个新线程");
}).start();
一些参数
一个箭头
一段代码
标准格式:
(参数类型 参数名称) -> { 代码语句/重写方法的代码 }
():接口中抽象方法的参数列表,没有参数,就空着;有参数就写出参数,多个参数使用逗号分隔。
->:把参数传递给方法体{}。
{}:重写接口的抽象方法。
Lambda的参数和返回值
Lambda标准模式(有参数有返回)
练习:使用Lambda省略格式
可推导可省略。
可省略的内容跟:
Lambda使用前提:
【备注:】有且仅有一个抽象方法的接口,称为“函数式接口”。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。