Java学习回忆录-基础理论-016
异常:
**概念: ** 程序运行中出现的问题.
**异常体系: **
java 是面向对象的,就将不同的问题,使用不同类来描述. ->产生一个问题时,就会一个对应的异常对象.
异常就组成了一个异常体系.
|---Throwable父类
Throwable 类是 Java 语言中所有错误或异常的超类。
(只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。)
上述描述, 只有是Throwable类本身,或者它的子类,创建对象,才称之为异常对象,才可以使用异常机制处理(抛出,捕获)
只有异常类,创建的对象,才能使用java的异常处理机制进行处理(抛出,捕获)
|---Error(错误)
Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题;
这类问题是比较严重的.
例如: 网络中断... b/s c/s i/O错误... 读写错误,硬盘坏了... 坏道...
java 程序不应该去捕获的.
|---Exception(异常)
Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。
这类问题,是程序员应该关注的.在代码程序需要处理的.
常见异常举例
数组: IndexOutOfBoundsException
NullPointerException
向下转型: ClassCastException
异常的分类:
运行时异常:RuntimeException
编译时异常:NoRuntimeException -> 凡是不属于RuntimeException,都属于编译时异常.
非运行的异常必须处理. 如果不处理,编译不通过, 程序无法运行.
异常处理:
解决方案一:
try{
可能出现异常的代码;
}catch(异常类 对象名){
处理异常的代码;
通常. ->e.printStackTrace(); ->追踪异常信息.
}
解决方案二:
当不会处理这个异常. 或者不能处理时,可以直接抛出处理.
在方法上. throws new 异常对象();
调用一个生命了异常的方法时, 需要进行处理,好么try catch 要么 继续抛出...
多线程概述.
**串行: ** 执行按照顺序依次执行.
**并发: ** 计算机可以同时执行多个程序
**进程: ** 一个正在执行的程序.
保存在硬盘中的程序不是进程,只有程序运行了,加载内存(开辟空间了),称之为一个进程.
进程和进程之间,共享操作系统的资源(cpu,内存,硬盘,网络)
**线程: ** 是进程中的基本单元,是进程中一个具体的执行单元(路径).
一个进程内部,可以有一个线程.->单线程的程序.
一个进程内部,可以有多个线程->多线程程序.
一个进程内部的线程,共享这个进程的资源(内存)
**多线程: ** 一个进程内部,可以有多个线程同时执行. 这其实也是并发的思想.
**多线程的意义(并发的意义) **
提高计算机资源的利用率,太高程序执行的效率.
不一定会让你的程序变快,有可能变慢的.
线程的生命周期
- 新建状态: 一个新产生的线程从新状态开始了它的生命周期。它保持这个状态直到程序start这个线程。
- **运行状态:**当一个新状态的线程被start以后,线程就变成可运行状态,一个线程在此状态下被认为是开始执行其任务
- **就绪状态:**当一个线程等待另外一个线程执行一个任务的时候,该线程就进入就绪状态。当另一个线程给就绪状态的线程发送信号时,该线程才重新切换到运行状态。
- 休眠状态: 由于一个线程的时间片用完了,该线程从运行状态进入休眠状态。当时间间隔到期或者等待的事件发生了,该状态的线程切换到运行状态。
- 终止状态: 一个运行状态的线程完成任务或者其他终止条件发生,该线程就切换到终止状态。
线程的优先级
每一个Java线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。Java优先级在MIN_PRIORITY(1)和MAX_PRIORITY(10)之间的范围内。默认情况下,每一个线程都会分配一个优先级NORM_PRIORITY(5)。
具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器时间。然而,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
Java多线程
**Thread类: ** 线程 是程序中的执行线程。Java虚拟机允许应用程序并发地运行多个执行线程。
Java创建线程的两种方式
创建新执行线程有两种方法。
方式一: 继承类
1. 一种方法是将类声明为 Thread 的子类。
2. 该子类应重写 Thread 类的 run 方法。
3. 接下来可以分配并启动该子类的实例,创建子类对象.
4.调用start方法,启动线程.
小结: 使用继承的方式创建了一个线程,并开启了线程.
注意: 创建线程,是通过创建Thread类的子类对象实现的, 开启线程,是通过start方法.而不是调用run方法。
弊端:
1. java 只支持单继承, 一个类只能有一个父类.
如果自定义类,已经有父类了, 那么我还还想开启和创建线程, 就无法再继承Thread 类.
2. 没有将线程和线程执行的任务,进行分离. 代码耦合性太高. 后续这种方式用的很少...
方式二: 实现接口.
1.声明类实现 Runnable 接口。
2.该类然后实现 run 方法。
3.然后可以分配该类的实例(创建对象)
4.在创建 Thread 时作为一个参数来传递并启动。
好处:
1. 解决了java 单继承问题,java 虽然只支持单继承,但是可以多现实..
2. 结构清晰,将线程线程需要执行的任务的代码分离开来,解耦了。
需要理解:
1. 创建的Runnable 接口的实现类对象. 其实在定义任务(线程需要完成的工作)
2. 想要完成任务. 创建Thread类对象. 通过Thread 类的构造方法,接收任务(Runnable 接口的实现类对象)
3. 任务可以有一个线程完成,也可以有多个线程来完成.
使用接口这种方式,实现的多线程,非常灵活的.
多线程顺序执行
在线程调用时 使用join方法 判断上个线程执行完没
1. 在线程2中判断线程1 执行完没 -- try 线程1.join catch
2. 在线程3中判断线程1 执行完没 -- try 线程2.join catch
还可以在主方法中使用join
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
还可以使用同步代码块
线程安全问题
多线程, 多个线程操作共享数据(修改),有可能就会出现线程安全问题.
三种多线程操作问题
- 脏读:一个线程读取到其他线程未提交的数据
- 不可重复读:一个线程在做操作的数据,被其他线程修改了。强调的是数据内容不一样。
- 幻读:T线程正在按照条件查询时候,其他线程新增或者删除了满足该条件的数据,导致T线程前后查询的数据数量不一致。强调的是数量不一样。
解决线程安全问题
方案一: 同步代码块.
synchronized(锁对象){
需要同步的代码;
}
注意: 不要同步循环. 这样你的程序就是单线程的程序.
一个线程获取cpu 执行权,抢到锁对象. 进入了同步代码,循环不结束,该线程无法离开不同代码. 就变为了单线程程序...
注意: 锁对象. 可有是任意类型的对象. 要保证锁的唯一性...
方案二: 同步方法.
public synchronized 返回值类型 方法名(参数列表){
需要同步的代码;
}
同步方法默认的锁对象是this.
注意: 如果你想要同步方法,默认的this锁对象有效,建议你使用接口的方式,创建线程,不建议使用继承的方法.