B站宋红康JAVA基础视频教程个人笔记chapter08-09(异常处理+多线程)

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线程池

如果并发的线程数量很多,并且每个线程都是执行一个很短的时间就结束了。这样频繁的创建线程就会大大的降低系统的效率,因为频繁的创建线程和销毁线程需要时间。因此可以创建多个线程,放到线程池中,使用完放回,可以避免频繁的创建和销毁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值