尚硅谷|异常处理&多线程

异常处理

体系结构

throwable:异常体系根父类

        --》:Error错误,不编写代码处理

               stackOverflowError,OutOfMemoryError

        --》:Exception异常,可以编写代码处理

                --》编译时异常(受检异常)

                ClassNotFoundException

                FileNotFoundException

                 IOEception

                --》运行时异常(非受检异常)

public class ExceptionTest {
    @Test
    public void test1(){
        int[] arr = new int[10];
        System.out.println(arr[10]);
    }
    @Test
    public void test2(){
        int[][] arr=new int[2][];
        System.out.println(arr[1][1]);
    }
    @Test
    public void test3(){
        Object obj = new String();
        Date date=(Date) obj;
    }
    @Test
    public void test4(){
        String str="123";
        str="abc";
        int i = Integer.parseInt(str);
    }
    @Test
    public void test5(){
        Scanner scan=new Scanner(System.in);
        int num=scan.nextInt();
        System.out.println(num);//用户输入abc并非整形数字会报异常,输入不匹配
    }
    @Test
    public void test6(){
        int num = 10;
        System.out.println(num/0);//算术异常
    }
}

异常处理

方式一:try-catch-finally

try-catch

声明多个catch结构,父类应声明在最下面

处理:public void printStackTrace()打印异常的详细信息

           public String getMessage()获取发生异常的原因

try中声明的变量出了try结构之后不可以再调用

实际开发时运行时异常通常不进行处理

编译时异常一定要处理否则不通过:ClassNotFoundException,FileNotFoundException,IOException

finally使用

finally中的代码一定会被执行

有些资源必须要手动关闭,比如输入流,输出流,数据库连接。这部分代码必须放到finally中

方式二:throws+异常类型

子类重写方法抛出的异常类型可以与父类相同或是父类异常的子类

比如这种情况:运行时调用子类的method方法,抛出的异常Exception catch无法捕获(与多态自洽)

public class ThrowsTest {
    public static void main(String[] args) {
        Father f1= new Son();
        try{
            f1.method();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
class Father{
    public void method()throws IOException{
        
    }
}
class Son extends Father{
    public void method()throws Exception{

    }
}

如何选择两种方式

>>try-catch-finally:资源一定要被执行,重写(父类无throws,子类只能trycatch)

>>a依次调用b,c,d方法,b\c\d之间递进,此时b\c\d有异常选择throws,而在a中使用try-catch-finally

手动抛出

需求

实际开发中出现不满足具体场景的问题,手动抛出异常

public class ThrowTest {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.register(-10);
        System.out.println(stu);
    }
}
class Student{
    int id;
    public void register(int id){
        if(id > 0){
            this.id=id;
        }else{
            throw new RuntimeException("输入id非法");
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                '}';
    }
}

自定义异常

需求:通过异常名称直接判别异常原因,因此自定义

通常继承于现有的异常体系RuntimeException\Exception

public class BelowZeroException extends Exception{
    static final long serialVersionUID = -6255851812010695214L;

    public BelowZeroException() {
    }

    public BelowZeroException(String message) {
        super(message);
    }

    public BelowZeroException(String message, Throwable cause) {
        super(message, cause);
    }
}

项目笔记

下面这段代码有什么问题呢?尚未解决。。。。。

        if (p instanceof Architect) {
            if (arcNum >= 1)
                throw new TeamException("团队中只能有一名架构师");
        } else if (p instanceof Designer) {
            if (desNum >= 2)
                throw new TeamException("团队中只能有两名设计师");
        } else {
            if (progNum >= 3)
                throw new TeamException("团队中只能有三名设计师");
        }

      /*  if (p instanceof Architect && arcNum >= 1) {
            throw new TeamException("团队中只能有一名架构师");
        } else if (p instanceof Designer && desNum >= 2) {
            throw new TeamException("团队中只能有两名设计师");
        } else if (p instanceof Programmer && progNum >= 3) {
            throw new TeamException("团队中只能有三名设计师");
        }*/

多线程

相关概念理解

进程,线程

线程隔离区:虚拟机栈,本地方法栈,程序计数器

线程共享区:方法区,堆

线程调度:分时调度,抢占式调度

单核/多核

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

并发:多个事件在同一时间段内发生。即在同一时间段内,多条指令在单个CPU上快速轮换,交替进行,宏观上看起来是多个事件同时进行

创建和启动线程

    Thread thread = new Thread(()->{
            System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().isDaemon());
            while (true){

            }
        },"aa");

实例化线程对象通过构造方法命名。

Java线程的三种命名方法 - 戈德里克山谷 - 博客园 (cnblogs.com)

方式1

创建线程匿名子类

public class DoubleThreadTest {
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                for(int i=1;i<=100;i++){
                    if(i%2==1)
                        System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                for(int i=1;i<=100;i++){
                    if(i%2==0)
                        System.out.println(Thread.currentThread().getName()+":"+ i);
                }
            }
        }.start();
    }
}

方式2

public class EvenNumberTest {
    public static void main(String[] args) {
        PrintNumber printNumber = new PrintNumber();
        Thread t1=new Thread(printNumber);
        t1.start();
    }
}

class PrintNumber implements Runnable{
    @Override
    public void run() {
        for (int i=0;i<100;i++)
            System.out.println(Thread.currentThread().getName()+ ":"+i);
    }
}

提供Runnable接口匿名实现类的匿名对象

public class DoubleThreadTest {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=1;i<100;i++){
                    if(i%2==1)
                        System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=1;i<100;i++){
                    if(i%2==0)
                        System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        }).start();
    }
}

Runnable适合共享数据处理,避免类的单继承性,实现代码和数据分类

Thread常用方法

构造器

常用方法

join():在线程a中通过线程b调用join(),意味着线程a进入阻塞状态,知道线程b执行结束,线程a才结束阻塞状态,继续执行。

yield()静态方法,一旦执行此方法,释放CPU的执行权

isAlive:判断是否存活

sleep():静态

线程优先级

默认优先级是5,设置范围是【1,10】,ctrl+F12查看

声明周期

JDK5之前:

JDK5之后

线程安全

同步监视器(锁):可以用任何一个类的对象充当,但是多个线程必须共用同一个锁

同步代码块

接口方式

同步监视器可以用this充当,只造了一个对象

public class WinTest {
    public static void main(String[] args) {
        Ticket ticket=new Ticket();
        Thread t1=new Thread(ticket);
        Thread t2=new Thread(ticket);
        Thread t3=new Thread(ticket);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class Ticket implements Runnable {
    @Override
    public void run() {
        synchronized (this){
            int ticket = 100;
            while (true) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "售票,票号为" + ticket);
                    ticket--;
                }else{
                    break;
                }
            }
        }
    }
}

继承方式

锁改成(类名.class),反射会讲

public class WindowTest {
    public static void main(String[] args) {
        SaleTicket s1=new SaleTicket();
        s1.setName("窗口1");
        SaleTicket s2=new SaleTicket();
        s2.setName("窗口2");
        SaleTicket s3=new SaleTicket();
        s3.setName("窗口3");
        s1.start();
        s2.start();
        s3.start();
    }
}

class SaleTicket extends Thread {
    static int ticket = 100;
    @Override
    public void run() {
        while (true) {
            synchronized (SaleTicket.class) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "售票,票号为" + ticket);
                    ticket--;
                }else{
                    break;
                }
            }
        }
    }
}

同步方法

操作共享数据的代码完整的声明在方法中,则将此方法声明为同步方法

synchronized修饰非静态方法,锁默认是this,比较适合修饰实现Runnabl接口类的方法。

synchronized修饰静态方法,锁默认是当前类。

线程安全懒汉式

方式1:

class Bank{
    private Bank(){}
    private static Bank instance=null;
    public static synchronized Bank getInstance(){//类只加载一次,同步监视器,默认为Bank.class
        if(instance==null){
            instance=new Bank();
        }
        return instance;
    }
}

方式2:同步代码块

class Bank{
    private Bank(){}
    private static Bank instance=null;
    public static Bank getInstance(){
        if(instance==null){
            synchronized (Bank.class) {
                if(instance==null){
                    instance=new Bank();
                }
            }
        }
        return instance;
    }
}

死锁

lock

1.确保多个线程共用同一个lock实例(考虑声明为 static )

2.执行lock方法

3.unlock

public class WindowTest {
    public static void main(String[] args) {
        SaleTicket s1=new SaleTicket();
        s1.setName("窗口1");
        SaleTicket s2=new SaleTicket();
        s2.setName("窗口2");
        SaleTicket s3=new SaleTicket();
        s3.setName("窗口3");
        s1.start();
        s2.start();
        s3.start();
    }
}

class SaleTicket extends Thread {
    static int ticket = 100;
    private static ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "售票,票号为" + ticket);
                    ticket--;
                }else{
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

线程间通信机制

案例:交替打印

public class PrintNumberTest {
    public static void main(String[] args) {
        PrintNumber p=new PrintNumber();
        Thread t1=new Thread(p,"线程1");
        Thread t2=new Thread(p,"线程2");
        t1.start();
        t2.start();
    }
}
class PrintNumber implements Runnable{
    int number =1;
    @Override
    public void run() {
        while(true){
            synchronized (this) {
                notify();
                if(number<=100) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":"+number);
                    number++;
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    break;
                }
            }
        }
    }
}

wait(),notify(),nitifyAll()的使用必须在同步代码块或同步方法中,并且方法的调用者必须是同步监视器。

消费者生产者案例

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值