一、异常

  • 指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
  • 异常体系
    • 根类

      • java.lang.Throwable

        • 两个直接子类

          • java.lang.Error

            • 严重错误Error,无法通过处理的错误,只能事先避免。
          • java.lang.Exception
            • 表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。
            • 这是我们平时所说的异常。

二、异常的处理

  • 五个关键字:try、catch、finally、throw、throws
  • throw
    • 可以使用 throw 关键字在指定的方法中抛出指定的异常。
    • 格式
      • throw new xxxException("异常产生的原因");
    • 注意事项
      • throw 关键字必须写在方法的内部。
      • throw 关键字后边 new 的对象必须是 Exception 或者 Exception 的子类对象。
      • throw 关键字抛出指定的异常对象,我们就必须处理这个异常对象。
        • throw关键字后边创建的是 RuntimeException 或者是 RuntimeException 的子类对象,我们可以不处理,默认交给JVM处理(打印异常对象,中断程序)
        • throw关键字后边创建的是编译异常(写代码的时候报错),我们就必须处理这个异常,要么throws,要么try...catch。
  • throws
    • 异常处理的第一种方式,交给别人处理。
    • 作用
      • 当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象。
      • 可以使用 throws 关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终交给JVM处理-->中断处理。
    • 格式:在方法声明时使用。
      • 修饰符 返回值类型 方法名(参数列表) throws 异常类名1,异常类名2...{}
    • 注意事项
      • throws 关键字必须写在方法声明处。
      • throws 关键字后边声明的异常必须是 Exception 或者是 Exception 的子类。
      • 方法内部如果抛出了多个异常对象,那么 throws 后边必须也声明多个异常。
        • 如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可。
      • 调用了一个声明抛出异常的方法,我们就必须的处理声明的异常。
        • 要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM。
        • 要么 try...catch 自己处理异常。
  • try..catch
    • 处理异常的第二种方式,自己处理异常。
    • 格式
      • try{

        • 可能产生异常的代码
      • }catch(异常类型   变量名){
        • 处理异常

          • 一般在工作中,会把异常的信息记录到一个日志中。
      • }
      • ...
      • catch(异常类型   变量名){
      • }
    • 注意事项
      • try 中可能会抛出多个异常对象,那么就可以使用多个 catch 来处理这些异常对象。
      • 如果 try 中产生了异常,那么就会执行 catch 中的异常处理逻辑,执行完毕 catch 中的处理逻辑,继续执行 try...catch 之后的代码。
      • 如果 try 中没有产生异常,那么就不会执行 catch 中异常的处理逻辑,执行完 try 中的代码,继续执行 try...catch 之后的代码。
  • finally 代码块
    • 格式

      • try{

        • 可能产生异常的代码
      • }catch(异常类型   变量名){
        • 处理异常

          • 一般工作中,会把异常的信息记录到一个日志中。
      • }
      • ...
      • catch(异常类型   变量名){
      • }finally{
        • 无论是否出现异常都会执行。
      • }
    • 注意事项
      • finally不能单独使用,必须和 try 一起使用。
      • finally 一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放 (IO) 。
  • 异常注意事项
    • 多个异常使用捕获如何处理

      • 多个异常分别处理。
      • 多个异常一次捕获,多次处理。
        • 我们常用的方式,处理时需要注意:
        • catch 里边定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在上边,否则就会报错。
      • 多个异常一次捕获一次处理。
    • 运行时异常被抛出可以不处理。即不捕获也不声明抛出。
      • 默认给虚拟机处理,终止程序。
    • 如果 finally 有 return 语句,永远返回 finally 中的结果,避免该情况。
    • 如果父类抛出多个异常,子类复写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
    • 父类方法没有抛出异常,子类重写父类方法时也不可抛出异常。
      • 此时子类产生异常,只能捕获处理,不能声明抛出。
  • 自定义异常
    • Java 提供的异常类,不够我们使用,需要自己定义一些异常类。
    • 格式
      • public  class  XXXExcepiton  extends  Exception | RuntimeException{

        • 添加一个空参数的构造方法
        • 添加一个带异常信息的构造方法
          • 查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息。
      • }
    • 注意事项
      • 自定义异常类一般都是以 Exception 结尾,说明该类是一个异常类。
      • 自定义异常类,必须的继承 Exception 或者 RuntimeException 。
        • 继承 Exception

          • 自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么 throws,要么 try...catch 。
        • 继承 RuntimeException
          • 自定义的异常类就是一个运行期异常,无需处理,交给虚拟机处理(中断处理)。

三、多线程

  • 并发与并行

    • 并发

      • 指两个或多个事件在同一时段内发生。
    • 并行
      • 指两个或多个事件在同一时刻发生(同时发生)。
  • 线程与进程
    • 进程

      • 是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
    • 线程
      • 线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
    • 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。
    • Java 程序属于抢占式调度,那个线程的优先级高,那个线程优先执行;同一个优先级,随机选择一个执行。
  • Thread 类
    • 构造方法

      • public   Thread();

        • 分配一个新的线程对象。
      • public   Thread(String   name)
        • 分配一个带指定名字的新的线程对象。
      • public   Thread(Runnable   target)
        • 分配一个带有指定目标的新的线程对象。
      • public   Thread(Runnable   target , String   name)
        • 分配一个带有指定目标的新的线程对象并指定名字。
    • 常用方法
      • String   getName()

        • 返回该线程的名称。
      • void   setName(String   name)
        • 改变线程名称,使之与参数 name 相同。
      • static   Thread   currentThread()
        • 返回对当前正在执行的线程对象的引用。
      • static   void   sleep(long   millis)
        • 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。

          • 毫秒数结束之后,线程继续执行。
  • 创建多线程
    • 第一种方式

      • 继承 Thread 类

        • 实现步骤

          • 创建一个 Thread 类的子类。
          • 在 Thread 类的子类中重写 Thread 类中的 run 方法,设置线程任务(开启线程要做什么?)
          • 创建 Thread 类的子类对象。
          • 调用 Thread 类中的方法 start 方法,开启新的线程,执行 run 方法。
            • void start()

              • 使该线程开始执行。
              • Java 虚拟机调用该线程的 run 方法
    • 第二种方式
      • 实现 Runnable 接口。
        • 实现步骤

          • 创建一个 Runnable 接口的实现类。
          • 在实现类中重写 Runnable 接口的 run 方法,设置线程任务。
          • 创建一个 Runnable 接口的实现类对象。
          • 创建 Thread 类对象,构造方法中传递 Runnable 接口的实现类对象。
          • 调用 Thread 类中的 start 方法,开启新的线程执行 run 方法。
    • 实现 Runnable 接口创建多线程程序的好处。
      • 避免了单继承的局限性
      • 增强了程序的扩展性,降低了程序的耦合性(解耦)。
        • 实现 Runnable 接口的方式,把设置线程任务和开启新线程进行了分离(解耦)。
        • 实现类中,重写了run方法:用来设置线程任务。
        • 创建 Thread 类对象,调用start方法:用来开启新线程。
  • 匿名内部类实现线程的创建
    • 格式

      • new 父类/接口(){

        • 重复父类/接口中的方法
      • }

四、线程安全

  • 通过模拟多窗口卖票引出线程安全问题。

    • 卖出不存在的票和重复的票。
  • 解决线程安全问题的方案
    • 使用同步代码块

      • 格式

        • synchronized (锁对象){

          • 能会出现线程安全问题的代码(访问了共享数据的代码)
        • }
      • 同步代码块中的锁对象,可以使用任意的对象。
      • 但是必须保证多个线程使用的锁对象是同一个。
      • 锁对象作用
        • 把同步代码块锁住,只让一个线程在同步代码块中执行。
    • 使用同步方法
      • 使用步骤

        • 把访问了共享数据的代码抽取出来,放到一个方法中。
        • 在方法上添加 synchronized 修饰符。
      • 格式
        • 修饰符 synchronized 返回值类型 方法名(参数列表){

          • 可能会出现线程安全问题的代码(访问了共享数据的代码)
        • }
      • 隐含的锁对象是谁
        • 非 static 方法

          • 谁调用这个方法,锁对象就是谁。

            • 也就是 this 。
        • satic 方法
          • 不能是 this

            • this 是创建对象之后产生的,静态方法优先于对象。
          • 是当前方法所在类的字节码对象(类名.class)。
    • 使用 Lock 锁
      • java.util.concurrent.locks.Lock接口

        • Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
      • Lock 接口中的方法
        • void lock()

          • 获取锁。
        • void unlock()
          • 释放锁。
      • 实现步骤
        • 在成员位置创建一个 ReentrantLock 对象。
        • 在可能会出现安全问题的代码前调用 Lock 接口中的方法 lock 获取锁。
        • 在可能会出现安全问题的代码后调用 Lock 接口中的方法 unlock 释放锁。

五、线程状态

  

  • Timed Waiting (计时等待)

    • 一个正在限时等待另一个线程执行一个(唤醒)动作的线程处于这一状态。
    • 进入到 TimeWaiting(计时等待) 有两种方式
      • 使用sleep(long  m) 方法

        • 在毫秒值结束之后,线程睡醒进入到 Runnable/Blocked 状态。
      • 使用wait(long  m) 方法
        • wait 方法如果在毫秒值结束之后,还没有被 notify 唤醒,就会自动醒来,线程睡醒进入到 Runnable/Blocked 状态。
    • 唤醒的方法
      • void   notify()

        • 唤醒在此对象监视器上等待的单个线程。
      • void   notifyAll()
        • 唤醒在此对象监视器上等待的所有线程。
  • BLOCKED (锁阻塞)
    • 一个正在阻塞等待一个监视器锁(锁对象)的线程处于这一状态。

      • 线程A与线程B代码中使用同一锁,如果线程 A 取到锁,线程 A 进入到 Runnable 状态,那么线程 B 就进入到 Blocked 锁阻塞状态。
  • Waiting (无限等待)
    • 一个正在无限期等待另一个线程执行一个特别的(唤醒)动作的线程处于这一状态。

      • 如何进入

        • void wait();
      • 如何唤醒
        • void notify()
        • void notifyAll()
    • 一个调用了某个对象的 Object.wait 方法的线程会等待另一个线程调用此对象的 Object.notify() 方法或 Object.notifyAll() 方法。
      • 也就是等待唤醒机制。

六、等待唤醒机制

  • 线程间通信

    • 概念

      • 多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。
    • 为什么要处理线程间通信
      • 多个线程并发执行时, 在默认情况下 CPU 是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。
    • 如何保证线程间通信有效利用资源
      • 多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。 就是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。也就是我们需要通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。
  • 等待唤醒机制
    • 就是在一个线程进行了规定操作后,就进入等待状态(wait()), 等待其他线程执行完他们的指定代码过后 再将其唤醒(notify());在有多个线程进行等待时, 如果需要,可以使用 notifyAll() 来唤醒所有的等待线程。

      • wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作,也即是“通知(notify)”在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中。
      • notify:选取所通知对象的 wait set 中的一个线程释放。
      • notifyAll:则释放所通知对象的 wait set 上的全部线程。
        • 注意

          • 哪怕只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。
      • 总结如下
        • 如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE 状态;
        • 否则,从 wait set 出来,又进入 entry set,线程就从 WAITING 状态又变成 BLOCKED 状态。
      • 细节
        • wait方法与notify方法必须要由同一个锁对象调用

          • 因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的 wait 方法后的线程。
        • wait方法与notify方法是属于Object类的方法的。
          • 因为:锁对象可以是任意对象,而任意对象的所属类都是继承了 Object 类的。
        • wait方法与notify方法必须要在同步代码块或者是同步函数中使用
          • 因为:必须要通过锁对象调用这2个方法。
  • 生产者消费者

七、线程池

  • 就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
  • java.util.concurrent.Executor
    • 线程池的顶级接口

      • 严格意义上讲并不是一个线程池,只是一个执行线程的工具。
      • 真正的线程池接口是 java.util.concurrent.ExecutorService。
  • java.util.concurrent.Executors
    • 线程池的工厂类,用来生成线程池。

      • static   ExecutorService   newFixedThreadPool(int    nThreads)

        • 创建一个可重用固定线程数的线程池。
        • int   nThreads
          • 创建线程池中包含的线程数量。
        • 返回值
          • 返回的是 ExecutorService 接口的实现类对象,我们可以使用 ExecutorService 接口来接收。
          • 面向接口编程。
        • 获取到了一个线程池 ExecutorService 对象,如何使用。
          • public   Future<?>   submit(Runnable   task)

            • 获取线程池中的某一个线程对象,并执行。
            • Future 接口
              • 用来记录线程任务执行完毕后产生的结果。
          • void   shutdown()
            • 关闭/销毁线程池。
    • 线程池使用步骤
      • 使用线程池的工厂类 Executors 里边提供的静态方法 newFixedThreadPool 生产一个指定线程数量的线程池。
      • 创建一个类,实现Runnable接口,重写run方法,设置线程任务。
      • 调用 ExecutorService 中的方法 submit ,传递线程任务(实现类),开启线程,执行run方法。
      • 调用 ExecutorService 中的方法 shutdown 销毁线程池(不建议执行)。
        • 线程池都没有了,就不能获取线程了。

八、Lambda 表达式

  • 引入

    • 传统通过匿名内部类创建多线程方式

      • 部分代码

        • new Thread(new Runnable(){

          • @Override
          • public void run() {
            • System.out.println(Thread.currentThread().getName()+" 新线程创建了"
          • }
        • }).start();
      • 使用Lambda表达式写法
        • new Thread(()->{

          •  System.out.println(Thread.currentThread().getName()+" 新线程创建了");
          • }
        • ).start();
      • 优化省略Lambda写法
        • new Thread(()->System.out.println(Thread.currentThread().getName()+" 新线程创建了")).start();
  • 2014年3月 Oracle 所发布的 Java 8(JDK 1.8)中,加入了Lambda表达式的重量级新特性,为我们打开了新世界的大门。
    • Lambda表达式的标准格式

      • 由三部分组成

        • 一些参数
        • 一个箭头
        • 一段代码
      • 格式
        • (参数列表) ->{一些重写的方法}
      • 解释
        • ()

          • 接口中抽象方法的参数列表,没有参数,就空着;有参数就写出参数,多个参数使用逗号分隔。
        • ->
          • 传递的意思,把参数传递给方法体 {}。
        • {}
          • 重写接口的抽象方法的方法体。
    • 省略格式
      • Lambda表达式:是可推导,可以省略。

        • 凡是根据上下文推导出来的内容,都可以省略书写。
        • 可省略的内容
          • 参数列表

            • 括号中参数列表的数据类型,可以省略不写。
            • 括号中的参数如果只有一个,那么类型和 () 都可以省略。
          • 一些代码
            • 如果 {} 中的代码只有一行,无论是否有返回值,都可以省略({},return,分号) 

              • 注意:要省略 {},return。分号必须一起省略

九、异常、多线程、Lambda 表达式完结

07.异常、多线程、Lambda 表达式的更多相关文章

  1. Java 多线程 -- lambda 表达式推导

    jdk 8 开始 java 引入了lambda 表达式. lambda适用场景: 1.接口或父类 2.接口或父类只有一个方法 我们从多线程写法来推导一下: 1.外部类写法: package com.x ...

  2. 转:【More Effective C#】Lambda表达式优化

    http://www.cnblogs.com/kongyiyun/archive/2010/10/19/1855274.html 使用Lambda表达式将会造成Lambda表达式主题部分的代码重复. ...

  3. Lambda表达式 简介 语法 示例

    Lambda 表达式也称为闭包,是匿名类的简短形式.Lambda 表达式简化了[单一抽象方法声明接口]的使用,因此 lambda 表达式也称为功能接口. 在 Java SE 7 中,单一方法接口可使用 ...

  4. Lambda 表达式的示例-来源(MSDN)

    本文演示如何在你的程序中使用 lambda 表达式. 有关 lambda 表达式的概述,请参阅 C++ 中的 Lambda 表达式. 有关 lambda 表达式结构的详细信息,请参阅 Lambda 表 ...

  5. Lambda 表达式的示例

    本文中的过程演示如何使用 lambda 表达式. 有关 lambda 表达式的概述,请参见 C++ 中的 Lambda 表达式. 有关 lambda 表达式结构的更多信息,请参见 Lambda 表达式 ...

  6. Lambda表达式 简介 语法 示例 匿名内部类

    在AS中使用 Lambda 表达式 Demo地址:https://github.com/baiqiantao/MultiTypeTest.git Gradle(Project级别)中添加classpa ...

  7. Lambda 表达式的演示样例-来源(MSDN)

    本文演示怎样在你的程序中使用 lambda 表达式. 有关 lambda 表达式的概述.请參阅 C++ 中的 Lambda 表达式. 有关 lambda 表达式结构的具体信息,请參阅 Lambda 表 ...

  8. Java8新特性(1):Lambda表达式

    Lambda表达式可以理解为一种匿名函数:没有名称,但有参数列表.函数主体.返回类型.它是行为参数化的一种实现,行为参数化是指将不同的行为作为参数传递给方法,方法的所具备的能力取决于它接收的行为参数. ...

  9. 01 语言基础+高级:1-7 异常与多线程_day07 【线程池、Lambda表达式】

    day07[线程池.Lambda表达式] 主要内容 等待与唤醒案例 线程池 Lambda表达式 教学目标 -[ ] 能够理解线程通信概念-[ ] 能够理解等待唤醒机制-[ ] 能够描述Java中线程池 ...

  10. C#多线程+委托+匿名方法+Lambda表达式

    线程 下面是百度写的: 定义英文:Thread每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段,它 ...

随机推荐

  1. koa源代码解析

    koa不愧为小而美,主要代码很少.简单来说,1,koa封装了node的http.createServer((req,res)=>{})的入参req,res到ctx同名属性(一个自定义对象)中,并 ...

  2. 打包exe

    2.要打包的文件为多个py文件 这种情况一般你的代码较多,项目较大,可能你写了一个GUI界面py文件这个文件调用了其他文件的函数什么的,这个时候你需要生成spec文件来打包,这里假设你的要打包的主文件 ...

  3. SFINAE几种实现方式

    一.通过函数返回值实现 template<class T> typename std::enable_if<std::is_trivially_default_constructib ...

  4. Git 工作常用操作

    撤回commit 上一次提交的代码 git reset --soft HEAD^ HEAD^的意思是上一个版本,也可以写成HEAD~1 如果你进行了2次commit,想都撤回,可以使用HEAD~2 g ...

  5. v4l2编程

    一.video 4 linux 2 ,是linux中关于视频设备的内核驱动.在linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video 0下 二一般操作流程( ...

  6. FTP为什么越来越不好用了?要如何替代?

    FTP相信很多人都不陌生,作为世界范围内第一个文件传输协议,FTP解决了互联网文件传输需求,至今已被广泛使用30多年.但很多人现在慢慢发现,FTP越来越不好用了,或者说越来越无法满足自己需求了,这是为 ...

  7. JS学习-Canvas

    Canvas Canvas API 提供了一个通过JavaScript 和 HTML的<canvas>元素来绘制图形的方式.它可以用于动画.游戏画面.数据可视化.图片编辑以及实时视频处理等 ...

  8. promethus+grafana监控

    1.监控 MySQL (终端可以安装在任意主机,不一定按在mysql节点上,注:mysql版本需在5.5以上) I.首先在mysql中添加监控使用的用户: create user 'exp'@'%' ...

  9. el-table 如果文字过多展示...

    1 <el-table-column label="任务名称" width="120px" align="center" :show- ...

  10. MySQL-explain详解说明

    1.Explain介绍 在日常工作中, 我们会有时会开慢查询去记录一些执行时间比较久的SQL语句, 找出这些SQL语句后我们常常会用explain这个命令来查看一个这些SQL语句的执行计划, 查看该S ...