学习日记-day17-5.27
完成目标:
知识点:
1.日期相关类_Calendar日历类
常用方法:int get(int field) ->返回给定日历字段的值void set(int field, int value) :将给定的日历字段设置为指定的值void add(int field, int amount) :根据日历的规则,为给定的日历字段添加或者减去指定的时间量Date getTime():将Calendar转成Date对象field:代表的是日历字段-> 年 月 日 星期等,都是静态的 private static void calendar02() {Calendar calendar = Calendar.getInstance();//多态//int get(int field) ->返回给定日历字段的值int year = calendar.get(Calendar.YEAR);System.out.println("year = " + year);//void set(int field, int value) :将给定的日历字段设置为指定的值//calendar.set(Calendar.YEAR,2028);//System.out.println(calendar.get(Calendar.YEAR));//void add(int field, int amount) :根据日历的规则,为给定的日历字段添加或者减去指定的时间量calendar.add(Calendar.YEAR,-1);System.out.println(calendar.get(Calendar.YEAR));//Date getTime():将Calendar转成Date对象Date date = calendar.getTime();System.out.println("date = " + date);}扩展方法:void set(int year, int month, int date) -> 直接设置年月日=====================================================================================需求:键盘录入一个年份,判断这一年是闰年,还是平年步骤:1.创建Calendar对象2.创建Scanner对象,键盘录入一个年份3.调用set方法,传递年,月,日set(年,2,1) -> 国外是0-11,所以设置成2月就是代表3月 4.将day减1天(3月1日减1天,就是2月最后一天,知道2月最后一天了,就知道是平年还是闰年了)5.获取day判断平年还是闰年,输出结果 private static void calendar03() {//1.创建Calendar对象Calendar calendar = Calendar.getInstance();//2.创建Scanner对象,键盘录入一个年份Scanner sc = new Scanner(System.in);int year = sc.nextInt();//3.调用set方法,传递年,月,日//set(年,2,1) -> 国外是0-11,所以设置成2月就是代表3月calendar.set(year,2,1);//4.将day减1天(3月1日减1天,就是2月最后一天,知道2月最后一天了,就知道是平年还是闰年了)calendar.add(Calendar.DATE,-1);int day = calendar.get(Calendar.DATE);//5.获取day判断平年还是闰年,输出结果if (day==29){System.out.println("闰年");}else{System.out.println("平年");}}
知识点 | 核心内容 | 易混淆点 |
Date类弃用问题 | Date类中多个方法已被弃用,由Calendar类替代 | 弃用方法与新方法的对应关系 |
Calendar类特性 | 抽象类,需通过getInstance()静态方法获取对象 | 抽象类不能直接实例化的特性 |
月份表示差异 | 国外月份从0开始计数(0-11对应国内1-12月) | 月份数值需要+1才能对应国内习惯 |
Calendar核心字段 | YEAR/MONTH/DAY_OF_MONTH/HOUR/MINUTE/SECOND等时间字段 | 字段的静态属性和使用方式 |
关键方法应用 | get()获取字段值; set()设置字段值; add()时间量加减; getTime()转Date对象 | 方法参数中字段常量的使用 |
闰年判断案例 | 通过设置3月1日再减1天获取2月最后一天 | 时区对日期计算的影响 |
多态应用 | Calendar.getInstance()返回的是具体子类对象 | 实际运行时类型与声明类型差异 |
2.日期相关类_日期格式化类
1.概述:日期格式化类
2.构造:SimpleDateFormat(String pattern)
3.pattern:代表的是我们自己指定的日期格式字母不能改变,但是中间的连接符我们可以改变 yyyy-MM-dd HH:mm:ss | 时间字母表示 | 说明 |
| ------------ | ---- |
| y | 年 |
| M | 月 |
| d | 日 |
| H | 时 |
| m | 分 |
| s | 秒 |## 2.SimpleDateFormat常用方法1.String format(Date date) -> 将Date对象按照指定的格式转成String
2.Date parse(String source)-> 将符合日期格式的字符串转成Date对象 public class Demo03SimpleDateFormat {public static void main(String[] args) throws ParseException {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//1.String format(Date date) -> 将Date对象按照指定的格式转成StringString time1 = sdf.format(new Date());System.out.println("time1 = " + time1);//2.Date parse(String source)-> 将符合日期格式的字符串转成Date对象String time2 = "2000-10-10 10:10:10";Date date = sdf.parse(time2);System.out.println("date = " + date);}
}
知识点 | 核心内容 | 重点 |
SimpleDateFormat类概述 | 用于日期格式化的工具类,可将Date对象转换为指定格式的字符串,或反向解析字符串为Date对象 | 构造方法参数为日期模式字符串(字母不可变,连接符可自定义) |
日期模式规则 | y-年、M-月、d-日、H-时、m-分、s-秒; 大小写敏感(如M与m区分月与分) | 易混淆:MM(月) vs mm(分) |
format方法 | 将Date对象按模式格式化为字符串(如yyyy-MM-dd HH:mm:ss) | 输出结果与模式严格匹配 |
parse方法 | 将符合模式的字符串解析为Date对象 | 编译时异常需处理(ParseException);格式不匹配会报错 |
连接符自定义 | 模式中非字母符号(如/、-)可自由替换,但字母顺序不可变 | 错误示例:mm/dd/yyyy会导致“分日年月”逻辑混乱 |
3.日期相关类_jdk8新日期类
1.概述:LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日
2.获取:static LocalDate now() -> 创建LocalDate对象static LocalDate of(int year, int month, int dayOfMonth) -> 创建LocalDate对象,设置年月日 public class Demo04LocalDate {public static void main(String[] args) {//static LocalDate now() -> 创建LocalDate对象LocalDate localDate = LocalDate.now();System.out.println("localDate = " + localDate);//static LocalDate of(int year, int month, int dayOfMonth) -> 创建LocalDate对象,设置年月日LocalDate localDate1 = LocalDate.of(2000, 10, 10);System.out.println("localDate1 = " + localDate1);}
}### 1.2.LocalDateTime对象1.LocalDateTime概述:LocalDateTime是一个不可变的日期时间对象,代表日期时间,通常被视为年 - 月 - 日 - 时 - 分 - 秒。2.获取:
static LocalDateTime now() 创建LocalDateTime对象
static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) 创建LocalDateTime对象,设置年月日时分秒public class Demo05LocalDateTime {public static void main(String[] args) {//static LocalDateTime now() 创建LocalDateTime对象LocalDateTime localDateTime = LocalDateTime.now();System.out.println("localDateTime = " + localDateTime);//static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) 创建LocalDateTime对象,设置年月日时分秒LocalDateTime localDateTime1 = LocalDateTime.of(2000, 10, 10, 10, 10, 10);System.out.println("localDateTime1 = " + localDateTime1);}
}### 1.3.获取日期字段的方法 : 名字是get开头int getYear()->获取年份
int getMonthValue()->获取月份
int getDayOfMonth()->获取月中的第几天private static void get() {LocalDate localDate = LocalDate.now();//int getYear()->获取年份System.out.println(localDate.getYear());//int getMonthValue()->获取月份System.out.println(localDate.getMonthValue());//int getDayOfMonth()->获取月中的第几天System.out.println(localDate.getDayOfMonth());}### 1.4.设置日期字段的方法 : 名字是with开头LocalDate withYear(int year):设置年份
LocalDate withMonth(int month):设置月份
LocalDate withDayOfMonth(int day):设置月中的天数private static void with() {LocalDate localDate = LocalDate.now();//LocalDate withYear(int year):设置年份//LocalDate localDate1 = localDate.withYear(2000);//System.out.println(localDate1);//LocalDate withMonth(int month):设置月份//LocalDate localDate2 = localDate1.withMonth(10);//System.out.println("localDate2 = " + localDate2);//LocalDate withDayOfMonth(int day):设置月中的天数//LocalDate localDate3 = localDate2.withDayOfMonth(10);//System.out.println("localDate3 = " + localDate3);LocalDate localDate1 = localDate.withYear(2000).withMonth(10).withDayOfMonth(10);System.out.println("localDate1 = " + localDate1);}### 1.5.日期字段偏移设置日期字段的偏移量,方法名plus开头,向后偏移
设置日期字段的偏移量,方法名minus开头,向前偏移/*向后偏移 -> plus开头方法向前偏移 -> minus开头方法*/private static void plusAndMinus() {LocalDate localDate = LocalDate.now();// LocalDate localDate1 = localDate.plusYears(1L);// System.out.println("localDate1 = " + localDate1);LocalDate localDate1 = localDate.minusYears(1L);System.out.println("localDate1 = " + localDate1);}
### 2.1 Period 计算日期之间的偏差方法:static Period between(LocalDate d1,LocalDate d2):计算两个日期之间的差值getYears()->获取相差的年getMonths()->获取相差的月getDays()->获取相差的天private static void period() {LocalDate local1 = LocalDate.of(2022, 12, 12);LocalDate local2 = LocalDate.of(2021, 11, 11);Period period = Period.between(local2, local1);System.out.println(period.getYears());System.out.println(period.getMonths());System.out.println(period.getDays());}### 2.2 Duration计算时间之间的偏差1.static Duration between(Temporal startInclusive, Temporal endExclusive) -> 计算时间差
2.Temporal : 是一个接口实现类:LocalDate LocalDateTime
3.参数需要传递 Temporal 的实现类对象, 注意要传递LocalDateTime因为Duration计算精确时间偏差,所以需要传递能操作精确时间的 LocalDateTime
4.利用Dutation获取相差的时分秒 -> to开头toDays() :获取相差天数toHours(): 获取相差小时toMinutes():获取相差分钟toMillis():获取相差秒(毫秒)private static void duration() {LocalDateTime local1 = LocalDateTime.of(2022, 12, 12,12,12,12);LocalDateTime local2 = LocalDateTime.of(2021, 11, 11,11,11,11);Duration duration = Duration.between(local2, local1);System.out.println(duration.toDays());System.out.println(duration.toHours());System.out.println(duration.toMinutes());System.out.println(duration.toMillis());}如果计算年月日 ,就用Period如果计算时分秒,就用Duration## 3.DateTimeFormatter日期格式化类1.获取:static DateTimeFormatter ofPattern(String pattern) -> 获取对象,指定格式
2.方法:String format(TemporalAccessor temporal)-> 将日期对象按照指定的规则转成String TemporalAccessor:接口,子接口有TemporalTemporal的实现类:LocalDate LocalDateTime TemporalAccessor parse(CharSequence text)-> 将符合规则的字符串转成日期对象 如果想将TemporalAccessor转成我们常见的LocalDateTime日期对象,就需要用到LocalDateTime中的静态方法:static LocalDateTime from(TemporalAccessor temporal) private static void parse() {DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");String time = "2000-10-10 10:10:10";TemporalAccessor temporalAccessor = dtf.parse(time);//System.out.println(temporalAccessor);LocalDateTime localDateTime = LocalDateTime.from(temporalAccessor);System.out.println("localDateTime = " + localDateTime);}
知识点 | 核心内容 | 易混淆点 |
LocalDate | 不可变日期对象,表示年月日; 创建方法:now()获取当前日期,of()设置指定日期 | getMonth()返回枚举类型 vs getMonthValue()返回数字 |
LocalTime | 不可变时间对象,表示时分秒; 同样使用now()和of()方法创建 | 与LocalDate的精度区别(是否包含时分秒) |
LocalDateTime | 不可变日期时间对象,组合LocalDate和LocalTime; 精确到纳秒级 | 必须使用LocalDateTime进行精确时间计算 |
字段操作 | get开头方法获取字段值; with开头方法设置字段值(返回新对象); plus/minus方法进行日期偏移 | 链式调用时注意不可变性(每次操作生成新对象) |
Period | 计算两个LocalDate之间的年月日差值; between()方法+getYears/Months/Days获取结果 | 直接相减(2022-12 vs 2021-11 → 1年1月) |
Duration | 计算两个LocalDateTime之间的精确时间差; between()方法+toDays/Hours/Minutes获取结果 | 必须使用LocalDateTime作为参数 |
DateTimeFormatter | 替代SimpleDateFormat的格式化类; ofPattern()创建格式器; format()日期转字符串; parse()字符串转日期 | 需要TemporalAccessor接口处理,转换需通过LocalDateTime.from() |
4.工具类_System系统相关类
| 方法 | 说明 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| static long currentTimeMillis() | 返回以毫秒为单位的当前时间,可以测效率 |
| static void exit(int status) | 终止当前正在运行的 Java 虚拟机 |
| static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length | 数组复制<br>src:源数组<br>srcPos:从源数组的哪个索引开始复制<br>dest:目标数组<br>ldestPos:从目标数组哪个索引开始粘贴<br>length:复制多少个元素 |public class Demo01System {public static void main(String[] args) {//currentTimeMillis();//exit();arraycopy();}/*static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)src:源数组srcPos:从源数组的哪个索引开始复制dest:目标数组destPos:从目标数组的哪个索引开始粘贴length:复制多少个元素*/private static void arraycopy() {int[] arr1 = {1,2,3,4,5};int[] arr2 = new int[10];System.arraycopy(arr1,0,arr2,0,5);for (int i = 0; i < arr2.length; i++) {System.out.print(arr2[i]+" ");}}private static void exit() {for (int i = 0; i < 100; i++) {if (i==5){System.exit(0);}System.out.println("helloworld"+i);}}private static void currentTimeMillis() {long time = System.currentTimeMillis();System.out.println("time = " + time);}
}
知识点 | 核心内容 | 重点 |
System工具类概述 | 系统相关工具类,构造方法私有化,所有方法均为静态 | 工具类的通用设计特点:构造私有+静态方法 |
currentTimeMillis()方法 | 返回当前时间的毫秒值,用于代码执行效率测试 | 注意时间戳的获取时机和差值计算 |
exit()方法 | 终止JVM运行,参数通常传0,会导致程序立即退出 | 与return语句的区别:影响整个虚拟机而非单个方法 |
arraycopy()方法 | 数组复制核心方法,5个参数:源数组、起始位、目标数组、起始位、复制长度 | 参数顺序和边界值容易混淆,需注意数组越界问题 |
工具类使用规范 | 通过类名直接调用静态方法,无需实例化 | 与普通类的实例化调用方式对比 |
5.工具类_Arrays数组工具类
| 方法 | 说明 |
| -------------------------------------------------- | ------------------------------------------- |
| static String toString(int[] a) | 按照格式打印数组元素<br>[元素1, 元素2, ...] |
| static void sort(int[] a) | 升序排序 |
| static int binarySearch(int[] a, int key) | 二分查找(前提是升序) |
| static int[] copyOf(int[] original, int newLength) | 数组扩容 |public class Demo02Arrays {public static void main(String[] args) {int[] arr = {5,3,4,6,5,4,7};System.out.println(Arrays.toString(arr));System.out.println("==============");Arrays.sort(arr);System.out.println(Arrays.toString(arr));System.out.println("==============");int[] arr1 = {1,2,3,4,5,6,7};int index = Arrays.binarySearch(arr1, 3);System.out.println("index = " + index);System.out.println("==============");int[] arr2 = {1,2,3,4,5};int[] newArr = Arrays.copyOf(arr2, 10);System.out.println(Arrays.toString(newArr));arr2 = newArr;System.out.println(Arrays.toString(arr2));}
}
知识点 | 核心内容 | 重点 |
Arrays工具类概述 | 构造私有、方法静态、类名直接调用 | 构造私有化的意义(防止实例化) |
toString()方法 | 按[元素1, 元素2...]格式打印数组 | 底层实现:StringBuilder拼接逻辑(判空、索引处理) |
sort()方法 | 数组升序排序(非冒泡排序,底层为优化算法) | 与手动实现冒泡排序的性能对比 |
binarySearch()方法 | 二分查找(前提:数组已升序) | 未排序时调用后果(结果错误) |
copyOf()方法 | 数组扩容(底层依赖System.arraycopy) | 扩容原理:新数组创建 + 老数据复制 |
方法封装思想 | 理解底层原理后复用封装方法 | 为什么先学手动实现(加深原理理解) |
6.包装类
1.概述:就是基本类型对应的类(包装类),我们需要将基本类型转成包装类,从而让基本类型拥有类的特性(说白了,将基本类型转成包装类之后,就可以使用包装类中的方法操作数据)2.为啥要学包装类:a.将来有一些特定场景,特定操作,比如调用方法传递包装类比如:ArrayList集合,里面有一个方法add(Integer i),此时我们不能调用add方法之后直接传递基本类型,因为引用类型不能直接接收基本类型的值,就需要先将基本类型转成包装类,传递到add方法中b.将来我们还可以将包装类转成基本类型:包装类不能直接使用+ - * /,所以需要将包装类转成基本类型,才能使用+ - * /| 基本类型 | 包装类 |
| -------- | --------- |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Charactor |
| boolean | Boolean |
### 2.1.Integer基本使用1.概述:Integer是int的包装类
2.构造: 不推荐使用了,但是还能用Integer(int value)Integer(String s) s必须是数字形式public class Demo01Integer {public static void main(String[] args) {Integer i1 = new Integer(10);System.out.println("i1 = " + i1);Integer i2 = new Integer("10");System.out.println("i2 = " + i2);System.out.println("================");Boolean b1 = new Boolean("true");System.out.println("b1 = " + b1);Boolean b2 = new Boolean("false");System.out.println("b2 = " + b2);Boolean b3 = new Boolean("True");System.out.println("b3 = " + b3);}
}===================================================1.装箱:将基本类型转成对应的包装类
2.方法:static Integer valueOf(int i) static Integer valueOf(String s) public class Demo02Integer {public static void main(String[] args) {Integer i1 = Integer.valueOf(10);System.out.println("i1 = " + i1);Integer i2 = Integer.valueOf("100");System.out.println("i2 = " + i2);}
}===================================================1.拆箱:将包装类转成基本类型
2.方法:int intValue();public class Demo03Integer {public static void main(String[] args) {Integer i1 = Integer.valueOf(10);System.out.println("i1 = " + i1);int i = i1.intValue();System.out.println("(i+10) = " + (i + 10));}
}
### 2.2.自动拆箱装箱1.拆箱和装箱很多时候都是自动完成的public class Demo04Integer {public static void main(String[] args) {Integer i = 10;//发生了自动装箱了Integer sum = i+10;//发生了自动拆箱装箱System.out.println("sum = " + sum);}
}public class Demo05Integer {public static void main(String[] args) {Integer i1 = 100;Integer i2 = 100;System.out.println(i1==i2);Integer i3 = 128;Integer i4 = 128;System.out.println(i3==i4);}}
## 3.基本类型和String之间的转换### 3.1 基本类型往String转1.方式1:+ 拼接
2.方式2:String中的静态方法static String valueOf(int i) private static void method01() {int i = 10;String s1 = i+"";System.out.println(s1+1);System.out.println("============");String s = String.valueOf(10);System.out.println(s+1);}===================================================
### 3.2 String转成基本数据类型每个包装类中都有一个类似的方法: parseXXX| 位置 | 方法 | 说明 |
| ------- | ------------------------------------- | ----------------------- |
| Byte | static byte parseByte(String s) | 将String转byte类型 |
| Short | static short parseShort(String s) | 将String转成short类型 |
| Integer | static int parseInt(String s) | 将String转成int类型 |
| Long | static long parseLong(String s) | 将String转成long类型 |
| Float | static float parseFloat(String s) | 将String转成float类型 |
| Double | static double parseDouble(String s) | 将String转成double类型 |
| Boolean | static boolean parseBoolean(String s) | 将String转成boolean类型 |private static void method02() {int number = Integer.parseInt("1111");System.out.println(number+1);}1.在实际开发过程中如何定义一个标准javabean定义javabean的时候一般会将基本类型的属性定义成包装类型的属性 public class User {//private int uid;//用户idprivate Integer uid;//用户idprivate String username;//用户名private String password;//密码public User() {}public User(Integer uid, String username, String password) {this.uid = uid;this.username = username;this.password = password;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}}
1.举例:如果uid为Integer型,默认值是null
2.将来javabean中的数据都是和数据库表联系起来的,我们可以将javabean中的数据添加到表中
如果表中的uid为主键自增的,此时添加语句时uid中的数据不用我们单独维护赋值了,添加语句的sql语句就可以这样写:
insert into user(uid,username,password) values (NULL,'金莲','36666');
3.到时候,我们需要将javabean中封装的数据获取出来放到sql语句中,如果uid为主键自增,而且javabean中的uid为包装类型,默认值为NULL,这样就不用单独维护uid的值了,也不用先给javabean中的uid赋值,然后在保存到数据库中了,咱们就可以直接使用uid的默认值,将默认值放到sql语句的uid列中
4.而且将javabean中的属性变成包装类,还可以使用包装类中的方法去操作此属性值。
知识点 | 核心内容 | 重点 |
包装类概念 | 基本数据类型对应的类,用于让基本类型拥有类特性(如方法调用) | int→Integer/char→Character与其他首字母大写规则不同 |
包装类作用 | 1. 使基本类型具备类特性; 2. 集合等场景强制要求包装类型; 3. 支持null值场景 | ArrayList的add方法必须传Integer类型 |
装箱拆箱机制 | 自动装箱:Integer i = 10; 自动拆箱:i+10 → 实际调用intValue() | 反编译可见编译器自动插入valueOf/intValue调用 |
缓存池机制 | -128~127范围的Integer对象复用(通过IntegerCache内部类实现) | new Integer(100)==Integer.valueOf(100) 结果不同 |
类型转换方法 | 1. parseInt():String转int; 2. valueOf():String转Integer | 数字格式异常风险(需处理NumberFormatException) |
JavaBean规范 | 基本类型属性应定义为包装类型: - 支持null值(如数据库主键自增场景); - 可使用包装类方法 | 默认值差异:int默认0 vs Integer默认null |
7.多线程
知识点 | 核心内容 | 重点 |
多线程基础 | 多线程是JAVA后期高阶部分的重要内容 | 多线程基础操作与高级应用的区别 |
进程定义 | 进程是内存中执行的应用程序,如QQ | 进程与程序的区别,进程是执行中的程序 |
线程定义 | 线程是进程中最小的执行单元,负责程序运行 | 线程与进程的关系,线程在进程内 |
多线程程序 | 一个进程中可以有多个线程,称为多线程程序 | 多线程与单线程的区别 |
线程与CPU | CPU为每一个功能开辟通道,即线程,去内存中提取代码执行 | 线程是CPU与内存之间的通道 |
多线程使用场景 | 耗时操作、拷贝大文件、加载大量资源、聊天软件、服务器等 | 多线程提高CPU利用率,但不能绝对说提高效率 |
并发与并行 | 并行:多个指令在多个CPU上同时执行;并发:多个指令在单个CPU上交替执行 | 并发与并行的区别,交替与同时的执行方式 |
CPU调度 | 分时调度:线程轮流获取CPU使用权;抢占式调度:线程抢占CPU使用权 | 两种调度方式的区别,JAVA程序使用抢占式调度 |
主线程概念 | 主线程是CPU和内存之间为main方法开辟的通道 | 主线程与程序执行的关系,main方法占一个线程 |
8.多线程_创建线程方式1_继承Thread
## 1.第一种方式_extends Thread1.定义一个类,继承Thread
2.重写run方法,在run方法中设置线程任务(所谓的线程任务指的是此线程要干的具体的事儿,具体执行的代码)
3.创建自定义线程类的对象
4.调用Thread中的start方法,开启线程,jvm自动调用run方法public class Test01 {public static void main(String[] args) {//创建线程对象MyThread t1 = new MyThread();//调用start方法,开启线程,jvm自动调用run方法t1.start();for (int i = 0; i < 10; i++) {System.out.println("main线程..........执行了"+i);}}
}public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("MyThread...执行了"+i);}}
}
知识点 | 核心内容 | 重点 |
创建多线程的第一种方式 | 通过继承Thread类实现多线程 | start()与run()方法的区别 |
Thread类结构 | Thread类实现Runnable接口并重写run()方法 | run()方法是线程任务执行入口 |
线程任务定义 | 在自定义线程类的run()方法中编写具体执行逻辑 | 线程任务代码需写在run()方法内 |
线程启动机制 | 必须调用start()方法才会真正创建新线程 | 直接调用run()只是普通方法调用 |
线程执行特性 | 多个线程会交替执行,顺序不确定 | CPU调度导致每次执行结果可能不同 |
代码实现示例 | MyThread继承Thread→重写run()→创建对象→调用start() | 完整实现步骤需严格遵循 |
9.多线程_多线程运行原理
知识点 | 核心内容 | 重点 |
多线程内存运行机制 | 主线程与自定义线程在内存中拥有独立的栈空间,分别执行对应方法(如main()和run()) | 线程栈空间独立性(开新线程即新建栈空间) |
线程启动规则 | 同一线程对象不可多次调用start(),需新建对象才能再次启动 | 重复调用start()会报异常 |
线程资源消耗 | 死循环创建线程会导致内存占满,系统无响应 | 实际应用需控制线程数量 |
线程生命周期 | 线程启动后执行run()方法,结束后栈空间释放 | 线程对象复用与新建的区别 |
10.多线程_Thread中常用方法
void start() -> 开启线程,jvm自动调用run方法
void run() -> 设置线程任务,这个run方法是Thread重写的接口Runnable中的run方法
String getName() -> 获取线程名字
void setName(String name) -> 给线程设置名字
static Thread currentThread() -> 获取正在执行的线程对象(此方法在哪个线程中使用,获取的就是哪个线程对象)
static void sleep(long millis)->线程睡眠,超时后自动醒来继续执行,传递的是毫秒值 public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 10; i++) {//线程睡眠try {Thread.sleep(1000L);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"...执行了"+i);}}
}public class Test01 {public static void main(String[] args) throws InterruptedException {//创建线程对象MyThread t1 = new MyThread();//给线程设置名字t1.setName("金莲");//调用start方法,开启线程,jvm自动调用run方法t1.start();for (int i = 0; i < 10; i++) {Thread.sleep(1000L);System.out.println(Thread.currentThread().getName()+"线程..........执行了"+i);}}
}问题:为啥在重写的run方法中有异常只能try,不能throws原因:继承的Thread中的run方法没有抛异常,所以在子类中重写完run方法之后就不能抛,只能try
知识点 | 核心内容 | 重点 |
Thread类方法 | start()方法开启线程并自动调用run()方法 | start()与run()方法的区别 |
run()方法 | 设置线程任务的核心方法, 需重写Runnable接口 | 父类Thread中的run()方法未抛异常,子类重写后不能throws |
线程命名 | getName()获取线程名 setName()设置线程名 | 主线程默认名为"main",新建线程默认名为"Thread-N" |
currentThread() | 静态方法获取当前执行线程的引用 | 链式调用获取线程名:Thread.currentThread().getName() |
sleep()方法 | 使线程暂停指定毫秒数(1000ms=1s) | 编译时异常必须处理,run()中只能try-catch |
线程执行控制 | sleep()不影响其他线程执行 | 主线程与子线程的执行顺序不确定性 |
异常处理规则 | 子类重写方法时异常声明需与父类一致 | Thread.run()未声明异常导致子类禁止throws |