文章目录
1.异常处理方式1:try-catch-finally
1.1基本结构
try{
}
catch(异常类型1 e){
}
catch(异常类型2 e){
}
finally{ // 无论异常是否发生都执行
}
1.2使用细节
1.将可能出现异常的代码声明再try语句中,一旦代码出现异常,就会自动生成一个对应异常类的对象。并将此对象抛出。
2.针对try中抛出异常类的对象,使用之后的catch语句进行匹配,一旦匹配上,就进入catch语句,一旦处理结束,代码继续向下执行
3.如果不同的异常类型存在子父类的关系,那么父类必须在下面
4.catch中异常处理的方式:4.1.自己编写输出语句 4.2.printStackTrace()打印异常的详细信息e.printStackTrace() 4.3.
e.getMessage()
1.3使用细节
1.编译时异常必须处理,否则编译不会通过
2.运行时异常一般需要修改代码,一般是自己编写代码的逻辑错误
1.4 啥样的代码一定要声明在finally中呢?
开发中,有一些资源比如IO流,数据库连接,Socket连接资源,使用完以后,必须显示的声明关闭操作,否则,GC不会自动回收这些资源。进而导致内存泄漏
2.异常处理方式1:throws
1.格式:
public void test() throws 异常类型1,异常类型2{
}
2.其他
子类的异常类型范围不能够大于父类
throw和throws的区别:前者用于产生异常,后者用于处理异常(排出,治理)
3.程序,进程,线程的区别
1.
**程序**
:为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象
2.**进程**
:程序的一次执行过程,就是正在内存中运行的应用采用程序(操作系统调度和分配资源的最小单位)
3.**线程**
:进程可以进一步细化为线程,是程序内部的一条执行路径,一个进程中至少有一个线程(CPU调度和执行的最小单位)
4.线程的创建
4.1线程的创建方式1:
public class EvenNumberTest {
public static void main(String[] args) {
// 3.创建当前Thread子类的对象
PrintNumber pn = new PrintNumber();
// 4.通过对象调用start,启动线程,调用当前线程的run方法
pn.start(); // 已经start的线程不能继续调用start,否则会出现线程状态异常
//main()方法线程执行的操作
for(int i=1;i<=10000;i++){
if(i%2==0){
System.out.println(Thread.currentThread().getName()+ ":" + i+"**********");
}
}
}
}
// 1.创建一个类继承于Thread
class PrintNumber extends Thread{
// 2.重写Thread中的run方法---》将此线程要执行的操作声明在此方法体中
@Override
public void run(){
for(int i=1;i<=10000;i++){
if(i%2==0){
System.out.println(Thread.currentThread().getName()+ ":" + i);
}
}
}
}
4.2线程的创建方式2:
// 线程创建方式二:实现Runnable接口
public class RunnableTest {
public static void main(String[] args) {
// 3.创建实例对象
EvenNumberPrint e1 = new EvenNumberPrint();
// 4.此对象传递到Thread的构造器中
Thread t1 = new Thread(e1);
// 5.Thread类的实例调用start() 1.启动线程 2.调用线程的run方法
t1.start();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
// 1.实现Runnable接口
class EvenNumberPrint implements Runnable {
// 2.重写run方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
5.线程类的常用方法和生命周期
1.start():启动线程,调用线程的run()方法
2.run():将线程要执行的操作,声明再run()方法
3.currentThread():获取当前执行代码的线程
4.getName():获取线程名
5.设置线程名:setName()
6.sleep(long millis):静态方法,调用时,可以使得当前线程睡眠指定毫秒数
7.yield():静态方法,一旦执行此方法,就释放CPU 的执行权
8.join():在线程a中通过调用线程b的join()方法,意味着线程a进入阻塞状态,直到线程b执行结束,线程a才结束阻塞状态,继续执行
9.isAlive():判断当前线程是否存活
5.1 线程的生命周期jdk5之前
6.线程的安全问题和同步机制
1.java是如何解决线程安全问题的?使用线程的同步机制
方式1:
同步代码块
synchronized(同步监视器){
// 需要被同步的代码
}
说明:
需要被同步的代码,就是哪些操作共享数据的代码
需要被同步的代码被sync包裹后,其他线程必须等待
同步监视器,俗称锁。那个线程获得了锁,哪个线程就执行需要被同步的代码
2.模拟三个窗口卖票的代码实现(同步代码块)
class SaleTicket implements Runnable {
int ticket = 100;
@Override
public void run() {
while(true) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (this) { // 这里的对象必须是同一个
if(ticket > 0) {
System.out.println(Thread.currentThread().getName() + "售票,票号为:" + ticket);
ticket--;
} else{
break;
}
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
SaleTicket s = new SaleTicket();
Thread t1 = new Thread(s);
Thread t2 = new Thread(s);
Thread t3 = new Thread(s);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
2.模拟三个窗口卖票的代码实现(同步方法)
class SaleTicket implements Runnable {
int ticket = 100;
boolean flag = true;
@Override
public void run() {
while (flag) {
show();
}
}
public synchronized void show() { // 这里需要是同一个对象,默认是this
try {
Thread.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 这里的对象必须是同一个
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "售票,票号为:" + ticket);
ticket--;
} else {
flag = false;
}
}
}
public class WindowTest {
public static void main(String[] args) {
SaleTicket s = new SaleTicket();
Thread t1 = new Thread(s);
Thread t2 = new Thread(s);
Thread t3 = new Thread(s);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
3.lock锁的使用
6.线程之间的通信
6.1为什么需要线程之间的通信
多个线程要完成
同一个任务
,但是又前后顺序,因此需要协调他们的工作
6.2两个线程交替打印1-100案例
class PrintNumber1 implements Runnable {
private int num = 1;
@Override
public void run() {
while (true) {
synchronized (this) {
notify(); // 一旦执行此方法,就会唤醒wait()中线程优先级最高的一个线程,被唤醒的线程从当初的wait线程开始执行
if (num <= 100) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + ": " + num);
num++;
try {
wait(); // 线程一旦执行此方法,就进入等待状态。会释放对同步监视器的调用
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
break;
}
}
}
}
}
public class PrintNumberTest {
public static void main(String[] args) {
PrintNumber1 printNumber1 = new PrintNumber1();
Thread thread1 = new Thread(printNumber1, "线程1");
Thread thread2 = new Thread(printNumber1, "线程2");
thread1.start();
thread2.start();
}
}
6.3线程池
如果并发的线程数量很多,并且每个线程都是执行一个很短的时间就结束了。这样频繁的创建线程就会大大的降低系统的效率,因为频繁的创建线程和销毁线程需要时间。
因此可以创建多个线程,放到线程池中,使用完放回,可以避免频繁的创建和销毁