Java学习笔记——2021.12.9
IDEA的使用与多线程
程序、进程、线程
- 程序:是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
- 进程:是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期
进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域。 - 线程:进程可进一步细化为线程,是一个程序内部的一条执行路径。
若一个进程同一时间并行执行多个线程,就是支持多线程的。
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开
销小。
一个进程中的多个线程共享相同的内存单元/内存地址空间–>它们从同一堆中分配对象,可以
访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资
源可能就会带来安全的隐患。 - 并行: 多 个 CPU 同时执行多个任务。比如:多个人同时做不同的事 。
- 并发: 一 个 CPU( 采用时间片 同时执行多个任务。比如:秒杀、多个人做同一件事。
线程的创建和使用
- 方式一:继承于Thread类
1.创建一个继承于Thread类的子类;
2.重写Thread类的run()方法;–>将此线程要执行的操作声明在run()中;
3.创建Thread类的子类对象;
4.通过此对象调用start()方法;–>启用当前线程,调用当前线程的run()
若要再启动一个线程,需要重新创建一个线程对象,重新start(); - 方式二:实现Runnable接口
1.创建一个实现了Runnable接口的类;
2.实现类去实现Runnable中的抽象方法:run();
3.创建实现类的对象;
4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象;
5.通过Thread类的对象调用start(); - 优先选择方式二,没有类的单继承性的局限性,更适合来处理多个线程有共享数据的情况;
- 守护线程 vs 用户线程
唯一区别:判断JVM何时离开;
守护线程:用来服务用户线程,通过在start()方法前调用thread.setDaemon(true)可以把一个用户线程变成守护线程;
线程的生命周期
五种状态:
- 新建: 当 一个 Thread 类或其子类的对象被声明并创建时,新生的线程对象处于新建状态;
- 就绪: 处于 新建 状态的线程被 start() 后,将进入线程队列等待 CPU 时间片,此时它已具备了运行 的 条件 ,只是没分配到 CPU 资源;
- 运行: 当就绪的线程被调度 并 获得 CPU 资源 时 便进入运行状态, run() 方法定义了线程的操作和功能;
- 阻塞: 在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态;
- 死亡: 线程完成了它的全部工作或线程被提前强制性 地 中止 或出现异常导致结束;
线程的同步
- 方式一:同步代码块
synchronized(同步监视器){
需要被同步的代码
}
说明:操作共享数据的代码,即为需要被同步的代码;多个线程共同操作的变量即为共享数据;同步监视器,俗称:锁,任何一个类的对象,都可以充当锁,多个线程必须共用同一把锁。 - 方式二:同步方法
将要被同步的代码封装到方法中,在返回类型前 + synchronized - 死锁:
不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁;
出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续; - 方式三:lock锁:
1.实例化Reentrantlock:private Reentrantlock lock = new Reentrantlock();
2.调用lock():lock.lock();
3.调用解锁方法:unlock():lock.unlock();
线程的通信
- wait():一旦执行此方法,当前线程进入阻塞状态,并释放同步监视器;
- notify():唤醒被wait的一个线程,如果有多个 线程,就唤醒优先级高的那个线程;
- notifyAll():唤醒所有被wait的线程;
- 以上方法都要声明在同步代码块或同步方法中;调用者必须是同步代码块或同步方法的同步监视器,否则,会出现IllegalMonitorStateException异常;定义在java.lang.object类中;
JDK5.0新增线程创建方式
新增方式一:实现Callable接口
- 与Runnable接口不同:
相比run()方法,可以有返回值;
可以抛出异常;
支持泛型的返回值;
需要借助FutureTask类,比如获取返回结果; - Future接口:
可以对具体 Runnable 、 Callable 任务的执行结果进行取消、查询是否完成、获取结果等;
FutrueTask 是 Futrue 接口的唯一的实现类;
FutureTask 同时实现了 Runnable, Future 接口。它既可以作为Runnable 被线程执行,又可以 作为 Future 得到 Callable 的返回值; - 步骤:
1.创建一个实现Callable实现类;
2.实现call方法,将此线程需要执行的操作声明在call()中;
3.创建Callable接口实现类的对象;
4.将此Callable接口实现类的对象传递到FutureTask构造器中,创建FutureTask对象;
5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start();
6.获取Callable中call方法的返回值;
新增方式二:使用线程池(实际使用比较多
- 思路: 提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免 频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
- 好处:
1.提高响应速度 (减少了创建新线程的时间
2.降低资源消耗 (重复利用线程池中线程,不需要每次都创建
3.便于线程管理 - ExecutorService :真正的线程池 接口。常见子类 ThreadPoolExecutor
1.void execute(Runnable command) :执行任务 命令,没有返回值,一般用来执行Runnable
2.< T > Future< T > submit(Callable< T > task) task):执行任务,有返回值,一般又来执行Callable
3.void shutdown() :关闭连接池; - Executors :工具类、线程池的工厂类,用于创建并返回不同类型的线程池
1.Executors.newCachedThreadPool ()():创建一个可根据需要创建新线程的线程池;
2.Executors.newFixedThreadPool(n ); 创建一个可重用固定线程数的线程池;
3.Executors.newSingleThreadExecutor () :创建一个只有一个线程的线程池;
4.Executors.newScheduledThreadPool(n )):创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。 - 步骤:
1.提供指定线程数量的线程池
2.执行指定线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象;
3.关闭连接池;
常用类
String
- String 类 代表 字符串。 Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。
- String 是一个 final 类,代表 不 可变的 字符序列 。
- 字符串 是 常量 ,用双引号引起来表示。 它们 的值在创建之后不能更改 。
- String 对象的字符内容是存储在一个字符 数组 value[] 中。
- 常量与常量的拼接结果在常量池 。且常量池中不会存在相同内容的常量 。
- 只要其中有一个是变量 结果就在堆中。
- 如果拼接的结果调用 intern() 方法 返回值就在常量池中。
- String采用方法:
StringBuffer
- java . StringBuffer代表可变的字符序列,JDK1.0 中声明,可以对字符串内容进行增删,此时不会产生新的对象。
- 很多方法与String相同。
- 作为参数传递时,方法内部可以改变值。
- tringBuffer类不同于String,其对象必须使用构造器生成。有三个构造器:
1.StringBuffer():初始容量为16的字符串缓冲区;
2.StringBuffer(int size):构造指定容量的字符串缓冲区;
3.StringBuffer(String str):将内容初始化为指定字符串内容。 - 常用方法:
java.lang.System类
- System类提供的 public static long currentTimeMillis()用来返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。
java.util.Date类
- Date():使用无参构造器创建的对象可以获取本地当前时间。
- Date(long date)
- getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来,此 Date 对象表示的毫秒数。
- toString():把此 Date 对象转换为以下形式的 String dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue,Wed, Thu, Fri, Sat) zzz是时间标准 。
java.text.SimpleDateFormat类
- Date类的 API 不易于国际化,大部分被废弃了 java.text.SimpleDateFormat类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
- 它允许进行格式化:日期–>文本 、 解析:文本–>日期;
- 格式化:
1.SimpleDateFormat () :默认的模式和语言环境创建对象;
2.public SimpleDateFormat (String 该构造方法可以用 参数 pattern指定的格式创建一个对象,该对象调用:
3.public String format(Date date) 方法格式化时间对象date - 解析:
public Date parse(String source) 从给定字符串的开始解析文本,以生成一个日期。
java.util.Calendar (日历)类
- Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。
- 获取Calendar实例的方法:
1.使用Calendar.getInstance()方法;
2.调用它的子类GregorianCalendar的构造器。 - 一个 Calendar 的实例是系统时间的抽象表示,通过 get( int field) 方法来取得想要的时间信息。比如 YEAR 、 MONTH 、 DAY_OF_WEEK 、 HOUR_OF_DAY 、MINUTE 、 SECOND
1.public void set( int field,int value)
2.public void add( int field,int amount)
3.public final Date getTime()
4.public final void setTime (Date date) - 注意:
获取月份时: 一月 是 0 ,二月是 1 ,以此类推 12 月是 11
获取星期时: 周日是 1 ,周二是 2 。 。。。周六是 7
JDK8中新日期时间API
- java.time:包含值对象的基础包
- java.time.chrono:提供对不同的日历系统的访问
- java.time.format:格式化和解析时间和日期
- java.time.temporal:包括底层框架和扩展特性
- java.time.zone:包含时区支持的类
- LocalDate、LocalTime、LocalDateTime类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO 8601 日历系统的日期、时间、日期和时间。它们提供了简单 的本地日期 或时间,并不包含当前的时间 信息,也 不包含与时区相关的信息 。
1.LocalDate 代表 IOS 格式( yyyy MM dd )的日期 可以存储 生日、纪念日等日期。
2.LocalTime 表示一个时间,而不是 日期 。
3.LocalDateTime 是用来表示日期和时间的, 这是一个最常用的类之一 。
- Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳 。
- java.time.format.DateTimeFormatter类:该类提供了三种格式化方法:
- 其他API:
1.ZoneId:该类中包含了所有的时区信息一个时区的ID,如Europe/Paris
2.ZonedDateTime:一个在 ISO 8601 日历系统时区的日期时间 如 2007 1203 T 10 15 30 01 00 Europe/Paris 。其中每个时区都对应着 ID 地区 ID 都为 区域 城市 的格式 例如:Asia/Shanghai 等
3.Clock 使用时区提供对当前即时 、 日期和时间的访问的时钟 。
4.持续时间:Duration用于计算两个时间间隔
5.日期间隔:Period用于计算两个日期间隔
6.TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。
7.TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/ 提供了大量的常用TemporalAdjuster 的实现 。
Java比较器
自然排序:java.lang.Comparable
- Comparable 接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。
- 实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小 。 如果当前对象 this 大于 形参对象 obj 则返回正整数,如果当前对象 this 小于 形参对象 obj 则返回负整数,如果当前对象 this 等于 形参对象 obj 则返回零 。
- 实现 Comparable 接口的对象列表(和数组)可以通过 Collections.sort 或Arrays.sort 进行 自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器 。
- 对于类 C 的每一个 e1 和 e2 来说,当且仅当 e1.compareTo(e2) == 0 与e1.equals(e2) 具有相同的 boolean 值时,类 C 的自然排序才叫做与 equals一致 。 建议(虽然不是必需的) 最好使自然排序与 equals 一致 。
- Comparable的典型实现:(默认都是从小到大排列的)
1.String :按照字符串中字符的 Unicode 值进行比较
2.Character :按照字符的 Unicode 值来进行比较
3.数值类型对应的包装类以及 BigInteger 、 BigDecimal :按照它们对应的数值大小进行比较
4.Boolean true 对应的包装类实例大于false对应的包装类实例
5.Date 、Time 等:后面的日期时间比前面的日期时间大
定制排序:java.util.Comparator
- 当元素的类型没有实现 java.lang.Comparable 接口而又不方便修改代码,或者实现了 java.lang.Comparable 接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来 排序强行对多个对象进行整体排序的比较。
- 重写 compare(Object o1,Object o2) 方法,比较 o1 和 o2 的大小: 如果方法返回正整数,则表示 o1 大于 o2 ;如果返回 0 ,表示相等;返回负整数,表示o1 小于 o2 。
- 可以 将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制 。
- 还可以使用 Comparator 来控制某些数据结构(如有序 set 或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序 。
System类
- System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包 。
- 由于 该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是 static 的,所以也可以很方便的进行调用 。
- 成员变量:System 类内部包含 in、out 和 err 三个成员变量,分别代表标准输入流(键盘输入 ),标准输出流(显示器)和标准错误输出流(显示器)。
- 成员方法:
1.native long currentTimeMillis():该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时间和 GMT 时间 格林威治时间 )1970 年 1 月 1 号 0 时 0 分 0 秒所差的毫秒数。
2.void exit(int status):该方法的作用是退出程序。其中 status 的值为 0 代表正常退出,非零代表异常退出。使用该方法可以在图形界面编程中实现程序的退出功能等。
3.void gc()该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则取决于系统中垃圾回收算法的实现以及系统执行时的情况。
4.String getProperty(String key)该方法的作用是获得系统中属性名为 key 的属性对应的值。系统中常见
的属性名以及属性的作用如下表所示:
Math类
- java.lang.Math提供了一系列静态方法用于 科学 计算。其 方法的参数和返回值类型一般为 double 型。
BigInteger类
- Integer 类作为 int 的包装类,能存储的最大整型值为 231-1 Long 类也是有限的,最大为 263 -1 。 如果 要表示再大的整数,不管是基本数据类型还是他们的包装类都无能为力,更不用说进行运算了。
- java.math 包的 BigInteger 可以表示不可变的任意精度的整数 。 BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。另外, BigInteger 还提供以下运算:模算术、 GCD 计算、质数测试、素数生成、位操作以及一些其他操作。
- 构造器:BigInteger (String val 根据字符串构建 BigInteger 对象
- 常用方法:
BigDecimal 类
- 一般的 Float 类和 Double 类可以用来做科学计算或工程计算,但在 商业计算中,要求数字精度比较高,故用到 java.math.BigDecimal 类 。
- BigDecimal 类支持不可变的、任意精度的有符号十进制定点数 。
- 构造器:
1.public BigDecimal(double val)
2.public BigDecimal (String val) - 常用方法:
1.public BigDecimal add (BigDecimal)
2.public BigDecimal subtract (BigDecimal)
3.public BigDecimal multiply (BigDecimal)
4.public BigDecimal divide (BigDecimal divisor, int scale, int roundingMode)
枚举类与注解
枚举类
- 类的对象只有有限个,确定的。称此类为枚举类;
方式一:自定义枚举类
- 声明Season对象的属性:private final修饰;
- 私有化类的构造器,并给对象属性赋值;
- 提供当前枚举类的多个对象public static final的修饰;
方式二:使用enum关键字定义枚举类
- 提供当前枚举类的对象,多个对象之间用“,”隔开,最后一个对象用“;”结束;
- 声明Season对象的属性:private final修饰;
- 私有化类的构造器,并给对象属性赋值;
- Enum类的主要方法:
- 使用enum关键字定义的枚举类实现接口的情况
1.实现接口,在enum类中实现抽象方法;
2.让枚举类的对象分别实现接口中的抽象方法;
注解Annotation
- Annotation 其实就是代码里的 特殊标记 , 这些标记可以在编译 , 类加载 , 运行时被读取 , 并执行相应 的处理。通过 使用 Annotation, 程序员可以在不改变原有逻辑的情况下 , 在源文件中嵌入一些 补充 信息 。 代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。
- Annotation 可以像修饰符一样被使用 , 可用于 修饰包 类 , 构造器 , 方法 , 成员变量 , 参数 , 局部变量的声明 , 这些信息被保存在 Annotation的 “name=value” 对中 。
- 在 JavaSE 中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE/Android 中注解占据了更重要的角色,例如用来配置应用程序的任何切面, 代替 JavaEE 旧版中所遗留的繁冗代码和 XML 配置等 。
- 未来的开发模式都是基于注解的, JPA 是基于注解的, Spring2.5 以上都是基于注解的, Hibernate3.x 以后也是基于注解的,现在的Struts2 有一部分也是基于注解的了,注解是一种趋势 ,一定程度上可以说:== 框架 = 注解 + 反射 + 设计模式==。
- 使用 Annotation 时要在其前面增加 @ 符号 , 并 把该 Annotation 当成一个修饰符使用。 用于修饰它支持的程序元素
- 示例一:生成文档相关的注解
@author标明开发该类模块的作者 多个作者之间使用 分割
@version标明该类模块的版本
@see参考转向 也就是相关主题
@since从哪个版本开始增加的
@param对方法中某参数的说明 如果没有参数就不能写
@return对方法返回值的说明 如果方法的返回值类型是 void 就不能写
@exception对方法可能抛出的异常进行说明 如果方法没有用 throws 显式抛出的异常就不能写
其中:
@param @return 和 @exception 这三个标记都是只用于方法的;
@param的格式要求: @param 形参名 形参类型 形参说明;
@return的格式要求: @return 返回值类型 返回值说明;
@exception的格式要求: @exception 异常类型 异常说明;
@param和 @exception 可以并列多个 ; - 示例二: 在编译时进行格式 检查 (JDK 内置的三个基本注解
@Override: 限定重写父类方法 , 该注解只能 用于方法;
@Deprecated : 用于表示所修饰的元素 类 , 方法等 已过 时。通常是因为所修饰的结构危险或存在更好的选择;
@SuppressWarnings :抑制编译器警告。 - 示例三: 跟踪 代码依赖性,实现替代配置文件功能;
自定义注解
- 注解声明为@interface;
- 内部定义成员,通常使用value表示;
- 可以指定成员的默认值,使用default来定义;
- 如果自定义注解没有成员,表明是一个标识作用;
- 如果注解有成员,在使用注解时,需要指明成员的值;
- 自定义注解必须配上注解的信息处理流程(使用反射)才有意义。
元注解
- 用于修饰其他注解的注解;
- @Retention只能用于修饰一个 Annotation 定义 , 用于指定该 Annotation 的生命周期 , @Rentention 包含一个 RetentionPolicy 类型的成员变量 , 使用Rentention 时必须为该 value 成员变量指定值。
- @Target用于修饰 Annotation 定义 , 用于指定被修饰的 Annotation 能用于修饰哪些 程序元素@Target 也包含一个名为 value 的 成员变量。
- @Documented用于指定被该元 Annotation 修饰的 Annotation 类将被javadoc 工具提取 成 文档。 默认情况 下 javadoc 是不包括注解 的 。
- @Inherited被它修饰的 Annotation 将 具有 继承性 。如果 某个类使用了被@Inherited 修饰的 Annotation, 则其子类将自动具有 该注解。