今日内容

  • 算法----------------->理解原理,做好笔记
    • 冒泡排序
    • 选择排序
    • 二分查找
  • 异常
    • 异常的概述
    • 异常的产生
    • 异常的处理-------------------->掌握
    • 自定义异常
  • 创建并启动线程的三种方式-------------------->掌握

第一章 冒泡排序

1.1 冒泡排序

  • 冒泡排序概述

    • 对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面
    • 每一轮比较完毕,最大值在最后面,下一轮比较就少一个数据参与
    • 每轮比较都从第一个元素(索引为0的元素)开始
    • 依次执行,直至所有数据按要求完成排序
    • 如果有n个数据进行排序,总共需要比较n - 1轮
  • 冒泡排序图解

    image-20210806092034753

  • 冒泡排序代码实现

    /**
     * Created by PengZhiLin on 2021/8/6 9:17
     */
    public class Test {
        public static void main(String[] args) {
            int[] arr = {45, 25, 35, 55, 15};
            // 冒泡排序
            // 外层循环控制比较的轮数
            for (int i = 0; i < arr.length - 1; i++) {
                // 内层循环控制每轮比较的次数
                for (int j = 0; j < arr.length - 1 - i; j++) {
                    // 比较并交换
                    if (arr[j] > arr[j+1]){
                        int temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
    
            System.out.println("排序后的数组:"+ Arrays.toString(arr));
        }
    }
    
    

第二章 选择排序

2.1 选择排序

  • 选择排序概述

    • 对要进行排序的数组中,选中某个位置元素(从头依次选中)依次和后面的元素逐个比较,将较大的数据放在后面
    • 每一轮比较完毕,最小值在最前面,下一轮比较就少一个数据参与
    • 每轮比较都从下一个(轮数+1)元素开始
    • 依次执行,直至所有数据按要求完成排序
    • 如果有n个数据进行排序,总共需要比较n - 1轮
  • 选择排序图解

    image-20210806095225943

  • 选择排序代码实现

    /**
     * Created by PengZhiLin on 2021/8/6 9:50
     */
    public class Test {
        public static void main(String[] args) {
            int[] arr = {45, 25, 35, 55, 15};
            // 选择排序
            // 外层循环控制比较的轮数
            for (int i = 0; i < arr.length - 1; i++) {
                // 内层循环控制每轮比较的次数
                for (int j = i + 1; j < arr.length; j++) {
                    // 比较并交换
                    if (arr[i] > arr[j]) {
                        int temp = arr[i];
                        arr[i] = arr[j];
                        arr[j] = temp;
                    }
                }
            }
    
            System.out.println("排序后的数组:" + Arrays.toString(arr));
        }
    }
    
    

第三章 二分查找

3.1 二分查找

  • 二分查找

    • 每一次都去获取数组的中间索引所对应的元素,然后和要查找的元素进行比对,如果相同就返回索引
    • 如果不相同,就比较中间元素和要查找的元素的值:
    • 如果中间元素的值大于要查找的元素,说明要查找的元素在左侧,那么就从左侧按照上述思想继续查询(忽略右侧数据);
    • 如果中间元素的值小于要查找的元素,说明要查找的元素在右侧,那么就从右侧按照上述思想继续查询(忽略左侧数据);
  • 前提:数据有序

  • 二分查找图解

    image-20210806101115492

  • 二分查找代码实现

    package com.itheima.demo3_二分查找;
    
    /**
     * Created by PengZhiLin on 2021/8/6 10:04
     */
    public class Test {
        public static void main(String[] args) {
            int[] arr = {10, 14, 21, 38, 45, 47, 53, 81, 87, 99};
            System.out.println(searchElement(arr, 53));// 6
            System.out.println(searchElement(arr, 50));// -1
        }
    
        // 定义一个方法,实现二分查找
        public static int searchElement(int[] arr, int num) {
            // 1.定义一个left变量,记录最左边元素的索引,初始值为0
            int left = 0;
    
            // 2.定义一个right变量,记录最右边元素的索引,初始值为数组长度-1
            int right = arr.length - 1;
    
            // 3.使用while循环查找,查找条件:left<=right
            while (left <= right) {
                // 4.在循环中,计算中间索引
                int middle = (left + right) / 2;
    
                // 5.判断中间索引对应的元素与要查找的元素是否相等
                if (arr[middle] == num) {
                    // 6.如果相等,就直接返回中间索引
                    return middle;
                }else if(arr[middle] > num) {
                    // 6.如果中间索引对应的元素 大于 要查找的元素,说明要查找的元素在左边,忽略右侧数据
                    right = middle - 1;
                }else if(arr[middle] < num)  {
                    // 6.如果中间索引对应的元素 小于 要查找的元素,说明要查找的元素在右边,忽略左侧数据
                    left = middle + 1;
                }
            }
    
            // 来到这里,说明没有找到,返回-1作为标识
            return -1;
        }
    }
    
    

第四章 异常

4.1 异常

异常概念

  • 概述: 指的是java程序运行期间出现的不正常情况,导致jvm终止程序的运行
  • 特点:
    • java是面向对象的语言,产生的每个异常其实都是一个异常对象,每个异常对象一定会有所属的异常类
    • 常见的异常类:
      • ClassCastException
      • NullPointerException
      • ArrayIndexOutOfBoundsException
      • ArithmeticException
      • ....
    • java中默认将异常抛给jvm处理,而jvm处理的方式就是中断程序运行,将异常信息输出到控制台

异常体系

  • Throwable类: 是 Java 语言中所有错误或异常类的父类
    • Error类(错误): 表示错误,不可以通过代码进行纠正使得程序继续运行,只能事先避免

      • eg: 栈内存溢出错误..... XXXError类
    • Exception类(异常):表示异常,可以通过代码进行纠正使得程序继续运行

      • eg: ClassCastException,NullPointerException,ArrayIndexOutOfBoundsException,ArithmeticException

异常分类

  • 编译异常: 程序在编译期间出现的异常,如果编译期间不处理,程序无法通过编译
    • 除了RuntimeException及其子类都是表示编译异常
  • 运行异常: 程序在运行期间出现的异常,如果不处理,程序可以通过编译,但在运行的时候会出现异常
    • RuntimeException及其子类都是表示运行异常

异常的产生过程解析

先运行下面的程序,程序会产生一个数组索引越界异常ArrayIndexOfBoundsException。我们通过图解来解析下异常产生的过程。

工具类

public class ArrayTools {
    // 对给定的数组通过给定的角标获取元素。
    public static int getElement(int[] arr, int index) {
        int element = arr[index];
        return element;
    }
}

测试类

public class ExceptionDemo {
    public static void main(String[] args) {
        int[] arr = { 34, 12, 67 };
        int num = ArrayTools.getElement(arr, 4);
        System.out.println("num=" + num);
        System.out.println("over");
    }
}

上述程序执行过程图解:

第五章 异常的产生和处理

5.1 异常的产生

throw关键字的作用

  • 在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。

  • throw用在方法内,来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行

throw关键字的使用格式

  • 格式: throw 异常对象;

  • 代码:

    
    /**
     * Created by PengZhiLin on 2021/8/6 10:58
     */
    public class Test {
        public static void main(String[] args) {
            System.out.println("开始");
            method1(10);
            System.out.println("结束");
        }
    
        public static void method1(int num){
            if (num == 10){
                // 可能会产生异常---创建异常对象
                // throw**用在方法内,来抛出一个异常对象**,将这个异常对象传递到调用者处,并**结束当前方法的执行**。
                throw new ArithmeticException("数学运算异常");
            }else{
                System.out.println("num不等于10");
            }
        }
    }
    
    

5.2 声明处理异常

  • 概述:使用throws关键字将异常标识出来, 表示当前方法不处理异常,而是提醒给调用者, 让调用者来处理....

  • 格式: 修饰符 返回值类型 方法名(形参列名) throws 异常类型1,异常类型2,...{}

  • 特点:

    • throws关键字是用在方法的声明之上的,也就是方法小括号的后面

    • throws可以一次抛一个或多个异常

    • 使用声明处理异常,处理完后,如果程序运行期间没有出现异常,程序可以继续往下执行

    • 使用声明处理异常,处理完后,如果程序运行期间有出现异常,程序不可以继续往下执行

    • 代码:

      /**
       * Created by PengZhiLin on 2021/8/6 11:08
       */
      public class Test {
          // 表示当前main方法不处理该异常,而是提醒调用者(jvm)来处理
          public static void main(String[] args) throws ParseException{
              /*
                   - 概述:使用**throws关键字**将异常标识出来, 表示当前方法不处理异常,而是提醒给调用者, 让调用者来处理....
                   - 格式:  `修饰符 返回值类型 方法名(形参列名) throws 异常类型1,异常类型2,...{}`
               */
              System.out.println("开始");
              //**使用声明处理异常,处理完后,如果程序运行期间出现了异常,程序不可以继续往下执行**
              //method(10);
              //**使用声明处理异常,处理完后,如果程序运行期间没有出现异常,程序可以继续往下执行**
              method(20);
              System.out.println("结束");
          }
      
          // 表示当前method方法不处理该异常,而是提醒调用者(main)来处理
          public static void method(int num) throws ParseException{
              if (num == 10){
                  // 产生一个异常
                  throw new ParseException("解析异常",num);
              }else{
                  System.out.println("num不等于10");
              }
          }
      }
      
      
  • 使用场景:

    • 用来处理编译异常,并且该程序在运行期间不会出现异常
  • 声明处理多个异常:

       // 表示当前method2方法不处理该异常,而是提醒调用者(main)来处理
        public static void method2(int num) throws ParseException,FileNotFoundException{
            if (num == 10){
                // 产生一个异常
                throw new ParseException("解析异常",num);
            }else{
                throw new FileNotFoundException("文件找不到异常");
            }
        }
    
        // 表示当前method3方法不处理该异常,而是提醒调用者(main)来处理
        public static void method3(int num) throws Exception{
            if (num == 10){
                // 产生一个异常
                throw new ParseException("解析异常",num);
            }else{
                throw new FileNotFoundException("文件找不到异常");
            }
        }
    

5.3 捕获处理异常try…catch

  • 概述: 也是一种处理异常的方式,这种处理异常的方式处理完异常后,无论程序是否发生异常,程序都可以继续往下执行.

  • 格式:

    try{
        // 可能会发生异常的代码
    }catch(异常类型 变量名){
        // 打印异常的信息,发生异常后需要执行的代码
    }
    // 继续往下执行
    
    • 注意:
      • try,catch都不能单独使用
      • try中的代码如果发生了异常,try中发生异常位置之后的代码就不执行了
  • 执行流程:

    • 首先执行try中的代码:
    • 如果try中的代码发生了异常,就会执行catch里面的代码,执行完catch里面的代码后,程序继续往下执行
    • 如果try中的代码没有发生异常,就不会执行catch里面的代码,而是继续往下执行
  • 代码:

    
    /**
     * Created by PengZhiLin on 2021/8/6 11:22
     */
    public class Test {
        public static void main(String[] args) {
    
            // 运行异常
            System.out.println("开始");
            try{
                System.out.println("try中发生异常前的代码");
                System.out.println(1/0);
                //System.out.println(1/1);
                System.out.println("try中发生异常后的代码");
            }catch (ArithmeticException e){
                System.out.println("发生了异常");
            }
            System.out.println("结束");
    
            // 编译异常
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                //Date date = sdf.parse("1999-10-10");
                Date date = sdf.parse("1999年10月10日");
                System.out.println(date);
            }catch (ParseException e){
                System.out.println("发生了解析异常");
            }
            System.out.println("结束");
    
        }
    }
    
    
  • 获取异常信息: ---->Throwable类

    • public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因

    • public String toString():获取异常的类型和异常描述信息(不用)

    • public void printStackTrace():打印异常的跟踪栈信息并输出到控制台

      /**
       * Created by PengZhiLin on 2021/8/6 11:22
       */
      public class Test1 {
          public static void main(String[] args) {
      
              // 运行异常
              System.out.println("开始");
              try{
                  System.out.println("try中发生异常前的代码");
                  System.out.println(1/0);
                  //System.out.println(1/1);
                  System.out.println("try中发生异常后的代码");
              }catch (ArithmeticException e){
                  System.out.println("异常信息:"+e.getMessage());
                  System.out.println("异常类型和异常信息:"+e.toString());
                  System.out.println("异常类型和异常信息:"+e);
                  e.printStackTrace();
              }
              System.out.println("结束");
      
              // 编译异常
              try {
                  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                  //Date date = sdf.parse("1999-10-10");
                  Date date = sdf.parse("1999年10月10日");
                  System.out.println(date);
              }catch (ParseException e){
                  System.out.println("异常信息:"+e.getMessage());
                  System.out.println("异常类型和异常信息:"+e.toString());
                  System.out.println("异常类型和异常信息:"+e);
                  e.printStackTrace();
              }
              System.out.println("结束");
      
          }
      }
      
      

5.4 finally 代码块

finally代码块的概述

finally:因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码在正常情况下一定会被执行的。

finally代码块的语法格式

try{
    可能会出现异常的代码
}catch(异常的类型 变量名){
    处理异常的代码或者打印异常的信息
}finally{
    无论异常是否发生,都会执行这里的代码(正常情况,都会执行finally中的代码,一般用来释放资源)
}

执行步骤:
 1.首先执行try中的代码,如果try中的代码出现了异常,那么就直接执行catch()里面的代码,执行完后会执行finally中的代码,然后程序继续往下执行
 2.如果try中的代码没有出现异常,那么就不会执行catch()里面的代码,但是还是会执行finally中的代码,然后程序继续往下执行

注意:finally不能单独使用。

案例演示

/**
 * Created by PengZhiLin on 2021/8/6 11:46
 */
public class Test {
    public static void main(String[] args) {
        // 快捷键: 选中代码块---->按ctrl+alt+t
        System.out.println("开始");
        try {
            System.out.println(1);
            System.out.println(1/0);// 发生异常
            //System.out.println(1/1);// 不发生异常
            System.out.println(2);
        } catch (ArithmeticException e) {
            System.out.println("发生了异常,异常的类型和信息:"+e);
            return;// 结束方法,finally会执行
            // System.exit(0);// 终止jvm,finally不会执行
        } finally {
            // finally中的代码正常情况无论是否发生异常都会执行,一般用来释放资源
            System.out.println("finally中的代码...");
        }
        System.out.println("结束");
    }
}

5.5 finally经典面试题


/**
 * Created by PengZhiLin on 2021/8/6 11:53
 */
public class Test {
    public static void main(String[] args) {
        System.out.println(method1());// 30
        System.out.println(method2());// 40
    }

    public static int method1() {
        int num = 10;
        try {
            System.out.println(1 / 0);
            num = 20;
        } catch (ArithmeticException e) {
            num = 30;
            // 执行catch中的return语句会做2件事:
            // 1.记录要返回的值,然后执行finally   ---->记录的是30
            // 2.返回之前记录的值,然后结束方法
            return num;
        } finally {
            num = 40;
        }
        return num;
    }

    public static int method2() {
        int num = 10;
        try {
            System.out.println(1 / 0);
            num = 20;
        } catch (ArithmeticException e) {
            num = 30;
            // 执行catch中的return语句会做2件事:
            // 1.记录要返回的值,然后执行finally   ---->记录的是30
            // 第二步就执行不了了
            return num;
        } finally {
            num = 40;
            return num;
        }
    }
}

5.6 处理异常注意事项

  • try/catch/finally都不可以单独使用

  • 运行时异常被抛出可以不处理(不捕获也不声明抛出),通过编译

  • 在try/catch后可以追加finally代码块,其中的代码一定会被执行,通常用于资源回收

  • 方法重写时的异常处理:

    • 父类的方法声明处理异常,子类覆盖(重写)父类方法时,只能声明相同的异常或该异常子集

    • 父类的方法未抛出的异常,子类覆盖(重写)父类方法时,只能捕获处理异常,不能声明处理异常

    • 代码:

      /**
       * Created by PengZhiLin on 2021/8/6 12:06
       */
      class Fu{
          public void method1() throws FileNotFoundException, IOException {
              
          }
          
          public void method2(){
              
          }
      }
      
      class Zi extends Fu{
          //- 父类的方法声明处理异常,子类覆盖(重写)父类方法时,只能声明相同的异常或该异常子集
          @Override
          public void method1() throws FileNotFoundException, IOException/*, ParseException 编译报错*/ {
              // 重写的method1方法中如果发生了解析异常,就得捕获处理
          }
      
          //- 父类的方法未抛出的异常,子类覆盖(重写)父类方法时,只能捕获处理异常,不能声明处理异常
          @Override
          public void method2() /*throws FileNotFoundException  编译报错*/{
             // method2方法中发生的异常,只能捕获处理
          }
      }
      public class Test1 {
          public static void main(String[] args) {
              
          }
          
         
      }
      
      
  • try...catch捕获多个异常的方式以及注意事项:

    public class Test1 {
        public static void main(String[] args) {
    
        }
    
        // 捕获处理多个异常: 多次捕获多次处理
        public static void method1(int num) {
            if (num == 10) {
                try {
                    throw new FileNotFoundException("文件找不到异常");
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            } else {
                try {
                    throw new IOException("IO异常");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        // 捕获处理多个异常: 一次捕获一次处理
        public static void method2(int num) {
            try {
                if (num == 10) {
                    throw new FileNotFoundException("文件找不到异常");
                } else {
                    throw new IOException("IO异常");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        // 捕获处理多个异常: 一次捕获多次处理
        public static void method3(int num) {
            try {
                if (num == 10) {
                    throw new FileNotFoundException("文件找不到异常");
                } else {
                    throw new IOException("IO异常");
                }
            } catch (FileNotFoundException e) {
                // 处理文件找不到异常的代码
            } catch (IOException e) {
                // 处理IO异常的代码
            }
        }
    
    }
    
    

第六章 自定义异常

6.1 自定义异常

  • 理解:在开发中根据自己业务的异常情况来定义异常类表示某种异常问题.

  • 原因:Java中异常类具备异常发生中断程序的功能,但一些异常情况是java没有定义的,需要根据业务自行定义(例:年龄负数问题)

  • 自定义异常类分类

    • 自定义编译期异常: 自定义类 并继承于java.lang.Exception

    • 自定义运行时期异常:自定义类 并继承于java.lang.RuntimeException

    • 案例:

      /**
       * Created by PengZhiLin on 2021/8/6 12:18
       */
      // 编译异常
      public class MyException1 extends Exception {
          public MyException1() {
          }
      
          public MyException1(String message) {
              super(message);
          }
      }
      
      
      /**
       * Created by PengZhiLin on 2021/8/6 12:18
       */
      // 运行异常
      public class MyException2 extends RuntimeException {
          public MyException2() {
          }
      
          public MyException2(String message) {
              super(message);
          }
      }
      
      
      /**
       * Created by PengZhiLin on 2021/8/6 12:18
       */
      public class Test1 {
          public static void main(String[] args) {
              // 创建自定义的编译异常对象
              //throw new MyException1("编译异常");
      
      
              // 创建自定义的运行异常对象
              throw new MyException2("运行异常");
          }
      }
      
      
  • 需求:按照如下要求完成案例

    • 模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册

      /**
       * Created by PengZhiLin on 2021/8/6 12:21
       */
      // 运行异常
      public class RegisterException extends RuntimeException {
      
          public RegisterException() {
          }
      
          public RegisterException(String message) {
              super(message);
          }
      }
      
      
      /**
       * Created by PengZhiLin on 2021/8/6 12:21
       */
      public class Test2_练习 {
          public static void main(String[] args) {
              // 模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册
              // 1.模拟数据库中已注册的用户名--->数组
              String[] names = {"张三","李四","王五"};
      
              // 2.用户输入用户名
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入要注册的用户名:");
              String name = sc.next();
      
              // 3.校验该用户名是否已经注册
              for (String s : names) {
                  if (s.equals(name)){
                      //注册了,就产生异常
                      throw new RegisterException("亲,该用户名已经被注册");
                  }
              }
      
              // 4.没有注册,就提示:恭喜,注册成功!
              System.out.println("恭喜,注册成功!");
      
          }
      }
      
      

第七章 多线程

我们在之前,学习的程序在没有跳转语句的前提下,都是由上至下依次执行,那现在想要设计一个程序,边打游戏边听歌,怎么设计?

要解决上述问题,咱们得使用多进程或者多线程来解决.

7.1 并发与并行

  • 并行:指两个或多个事件在同一时刻发生(同时执行)。
  • 并发:指两个或多个事件在同一个时间段内发生(交替执行)。

image-20220424232358286

7.2 线程与进程

  • 进程:进程是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;

    • 进程是应用程序的可执行单元也就是exe文件

    • 一个应用程序可以有多个进程

    • 每个进程执行都会有独立的内存空间

  • 线程:是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一条线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

    • 线程是进程的可执行单元
    • 一个进程可以有多条线程
    • 每个线程执行都会有独立的内存空间
  • java只有单进程,然后有多线程

  • 一个进程一次只能执行一条线程,所以java中只有多线程并发,没有多线程并行

  • 线程的调度方式:

    • 分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间
    • 抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性)
    • Java线程的调度方式: 抢占式

7.3 Thread类的api介绍

概述:
   java.lang.Thread类代表**线程**,所有的线程对象都必须是Thread类或其子类的实例
   每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码
   Java使用线程执行体来代表这段程序流,在Tread线程中,使用run()方法代表线程执行体
构造方法
    public Thread():创建一个新的线程对象,默认名称
    public Thread(String name):创建一个指定名字的新的线程对象    
       
    public Thread(Runnable target):创建一个带有指定任务的线程对象,通过参数Runnable指定任务
    public Thread(Runnable target,String name):创建一个带有指定任务的线程对象并指定线程名字
常用方法
    public String getName():获取当前线程名称
    public void start():导致此线程开始执行; Java虚拟机调用此线程的run方法
    public void run():此线程要执行的任务在此处定义代码
    public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停执行
    public static Thread currentThread()  :返回对当前正在执行的线程对象的引用
通过Thread类的api,可以指定创建线程有2种方式:
1.通过继承Thread类的方式
2.通过实现Runnable接口的方式

7.4 继承方式创建线程

  • 步骤:

    • 创建一个子类继承Thread类
    • 在子类中重写run方法,把线程需要执行的任务代码放入run方法中
    • 创建子类对象,调用start()方法启动线程,执行任务
  • 实现:

    
    /**
     * Created by PengZhiLin on 2021/8/6 15:24
     */
    public class MyThread extends Thread {
    
        @Override
        public void run() {
            // 线程的任务代码
            for (int i = 0; i < 100; i++) {
                System.out.println("子线程:HelloWorld...." + i);
            }
        }
    }
    
    
    /**
     * Created by PengZhiLin on 2021/8/6 15:24
     */
    public class Test {
        public static void main(String[] args) {// main方法在中主线程执行
            // 创建线程对象
            MyThread mt = new MyThread();
    
            // 启动线程执行任务代码
            mt.start();
    
            // 主线程再打印100次HelloWorld
            for (int j = 0; j < 100; j++) {
                System.out.println("主线程:HelloWorld...." + j);
            }
        }
    }
    
    

7.5 实现方式创建线程

  • Runnable是一个任务接口,里面有一个抽象方法run(),可以在run方法中书写线程的任务代码

  • 实现步骤:

    • 创建实现类实现Runnable接口
    • 在实现类中,重写run方法,把线程需要执行的任务代码放入run方法中
    • 创建实现类对象
    • 创建Thread线程对象,并传入实现类对象
    • 使用Thread线程对象调用start方法启动线程,执行任务
  • 实现:

    /**
     * Created by PengZhiLin on 2021/8/6 15:45
     */
    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            // 线程的任务代码
            for (int i = 0; i < 100; i++) {
                System.out.println("子线程:HelloWorld..." + i);
            }
        }
    }
    
    
    
    /**
     * Created by PengZhiLin on 2021/8/6 15:45
     */
    public class Test {
        public static void main(String[] args) {
            // 创建Runnable的实现类对象
            MyRunnable mr = new MyRunnable();
    
            // 创建Thread线程对象,传入实现类对象
            Thread t = new Thread(mr);
    
            // 调用start方法启动线程,执行任务
            t.start();
    
            // 主线程任务
            for (int j = 0; j < 100; j++) {
                System.out.println("主线程:HelloWorld..." + j);
            }
        }
    }
    
    

7.6 匿名内部类方式

  • 原理: 可以传入Runnable接口的匿名内部类

  • 步骤:

    • 创建Thread线程对象,并传入Runnable接口的匿名内部类
    • 在Runnable匿名内部类中重写run方法,书写线程需要执行的任务代码
    • 使用Thread线程对象调用start方法启动线程,执行任务
  • 实现:

    /**
     * Created by PengZhiLin on 2021/8/6 15:50
     */
    public class Test {
        public static void main(String[] args) {
            // 1.创建Thread线程对象,并传入Runnable接口的匿名内部类
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    // 2.在匿名内部类中重写run方法,书写线程任务代码
                    for (int i = 0; i < 100; i++) {
                        System.out.println("子线程:HelloWorld..."+i);
                    }
                }
            });
            // 3.调用start方法启动线程,执行任务代码
            t.start();
    
            // 主线程任务代码
            for (int j = 0; j < 100; j++) {
                System.out.println("主线程:HelloWorld..."+j);
            }
        }
    }
    
    

7.7 创建并启动多条线程

  • 通过继承的方式:

    /**
     * Created by PengZhiLin on 2021/8/6 15:56
     */
    public class MyThread extends Thread {
    
        public MyThread() {
        }
    
        public MyThread(String name) {
            super(name);
        }
    
        @Override
        public void run() {
            // 线程任务代码
            System.out.println(getName()+"子线程:开始执行任务代码...");
            // 暂停1000秒
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName()+"子线程:结束执行任务代码...");
        }
    }
    
    
    /**
     * Created by PengZhiLin on 2021/8/6 15:56
     */
    public class Test {
        public static void main(String[] args) {
            // 创建并启动多条线程
            MyThread mt1 = new MyThread("罗志祥");
            MyThread mt2 = new MyThread("吴签");
            MyThread mt3 = new MyThread("林俊杰");
            MyThread mt4 = new MyThread("潘玮柏");
            mt1.start();
            mt2.start();
            mt3.start();
            mt4.start();
    
            System.out.println("主线程的名称:"+Thread.currentThread().getName());
        }
    }
    
    
  • 通过实现的方式:

    
    /**
     * Created by PengZhiLin on 2021/8/6 16:05
     */
    public class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "子线程:任务代码...");
        }
    }
    
    
    /**
     * Created by PengZhiLin on 2021/8/6 16:05
     */
    public class Test {
        public static void main(String[] args) {
            // 创建任务实现类对象
            MyRunnable mr = new MyRunnable();
    
            // 创建并启动多条线程
            Thread t1 = new Thread(mr,"张柏芝");
            Thread t2 = new Thread(mr,"李小璐");
            Thread t3 = new Thread(mr,"白百何");
            Thread t4 = new Thread(mr,"马蓉");
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    
    

7.8 实现方式创建线程的优势

实现Runnable接口比继承Thread类所具有的优势:

  1. 适合多个相同的程序代码的线程去共享同一个资源(任务)。
  2. 可以避免java中的单继承的局限性。
  3. 增加程序的健壮性,实现解耦操作,任务代码可以被多个线程共享,任务代码和线程独立。
  4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

总结

必须练习:
    1.创建并启动线程的三种方式---->必须掌握
    2.创建并启动多条线程----->必须掌握
    3.异常的处理(声明处理,捕获处理)---->alt+回车--->选择处理方式
    4.冒泡排序和选择排序,二分查找要理解其原理,并做好笔记
    5.预习
    
- 能够理解冒泡排序的执行原理
    - 对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面
    - 每一轮比较完毕,最大值在最后面,下一轮比较就少一个数据参与
    - 每轮比较都从第一个元素(索引为0的元素)开始
    - 依次执行,直至所有数据按要求完成排序
    - 如果有n个数据进行排序,总共需要比较n - 1轮

- 能够理解选择排序的执行原理
   - 对要进行排序的数组中,使某个元素依次和后面的元素逐个比较,将较大的数据放在后面
    - 每一轮比较完毕,最小值在最前面,下一轮比较就少一个数据参与
    - 每轮比较都从下一个(轮数+1)元素开始
    - 依次执行,直至所有数据按要求完成排序
    - 如果有n个数据进行排序,总共需要比较n - 1轮

        
- 能够理解二分查找的执行原理
    - 每一次都去获取数组的中间索引所对应的元素,然后和要查找的元素进行比对,如果相同就返回索引
- 如果不相同,就比较中间元素和要查找的元素的值:
- 如果中间元素的值大于要查找的元素,说明要查找的元素在左侧,那么就从左侧按照上述思想继续查询(忽略右侧数据);
- 如果中间元素的值小于要查找的元素,说明要查找的元素在右侧,那么就从右侧按照上述思想继续查询(忽略左侧数据);

- 能够辨别程序中异常和错误的区别
    - Error类(错误): 表示错误,不可以通过代码进行纠正使得程序继续运行,只能事先避免
	- Exception类(异常):表示异常,可以通过代码进行纠正使得程序继续运行

- 说出异常的分类
   - 编译异常: 程序在编译期间出现的异常,如果不处理,程序无法通过编译
   - 运行异常: 程序在运行期间出现的异常,如果不处理,程序可以通过编译,但在运行的时候会出现异常

- 列举出常见的三个运行期异常
     ArrayIndexOutOfBoundsException
     NullPointerException
     ClassCastException
     ... 
       
- 能够使用try...catch关键字处理异常
    格式,执行流程
       
- 能够使用throws关键字处理异常
   格式,特点,使用场景
       
- 能够自定义并使用异常类
    创建异常类继承Exception或者RuntimeException
       
- 说出进程和线程的概念
    进程: 其实就是.exe文件
    线程: 其实就是进程的可执行单元
        
- 能够理解并发与并行的区别
     并发: 多个事件在同一时刻交替发生
     并行: 多个事件在同一时刻同时发生
         
- 能够使用继承类的方式创建多线程
     创建子类继承Thread类
     在子类中重写run方法,把线程需要执行的任务代码放入run方法中
     创建子类线程对象,调用start方法启动线程,执行任务
         
- 能够使用实现接口的方式创建多线程
     创建实现类实现Runnable接口
     在实现类中重写run方法,把线程需要执行的任务代码放入run方法中
     创建Thread类线程对象,并传入任务对象
     调用start方法启动线程,执行任务
         
- 能够说出实现接口方式的好处
    1. 适合多个相同的程序代码的线程去共享同一个资源(任务)。
    2. 可以避免java中的单继承的局限性。
    3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
    4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。


  
posted on 2022-04-24 23:41  ofanimon  阅读(30)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css