Java内存模型
一种符合计算机内存模型规范的,屏蔽了各种硬件和操作系统的访问差异,保证了Java程序在各种平台下对内存的访问都能得到一致性效果的一种机制以及规范
Java内存结构
- 栈内存(常用):存储方法的区域,方法运行时进入栈内存,方法运行结束,出栈内存,栈内存管理特点,先进后出
- 堆内存(常用):存储对象和数组,new来创建的,都是存储在堆内存中
- 方法区(常用):存储类文件,包含了一个类中的所有内容,常量
- 程序计数器
- 本地方法区
线程
一个独立的执行路径,存在于进程中,一个进程至少有一个线程。
并行和并发
并行:多个CPU同时执行多个任务
并发:一个CPU同时执行多个任务
多线程实现方式
继承Thread类
步骤:
- 自定义一个类,继承Thread类
- 重写Thread类中的run方法,用于定义新的要执行的内容
- 创建自定义类型的对象
- 调用线程开启的方法,start()方法
实现Runnable接口
步骤:(或者可用匿名内部类的方式)
- 定义一个任务类,实现Runnable接口
- 重写接口中的run方法,用于定义任务内容
- 创建任务类对象,表示任务
- 创建Thread类对象,将任务对象作为构造方法的参数传递,用于执行任务的类对Thread(Runnable r)
- 调用线程开启的方法,start()开启新线程
实现Callable接口
思路:
如果创建Thread,执行Runnable任务,需要Runnable对象
Runnable是一个接口,有一个特殊的实现类
FutureTask是Runnable的一个实现类
FutureTask在创建对象的时候,需要传递Callable的对象(FutureTask没有空参构造)
Callable是一个接口,所以需要一个Callable的实现类对象
步骤:
- 定义一个自定义类实现Callable接口
- 在自定义类中重写call()方法
- 创建自定义类对象
- 创建FutureTask对象,把自定义类的对象作为构造方法的参数传递给FutureTask
- 创建Thread类对象,把FutureTask对象作为构造方法的参数
- 使用Thread类对象调用start方法启动线程
- FutureTask对象调用get方法,可以获取到线程运行结束之后的结果
call()方法就相当于run()方法
call()方法与run()方法区别:
run没有任何方法的返回值结果,也不能抛出任何异常
call方法中可以有返回值,也可以抛出异常
守护线程
后台线程也被称为守护线程,守护线程是用来提供服务的
特点:如果一个程序的运行中,没有非守护线程,只有守护线程,那么守护线程运行一段时间之后,会自己停止
setDaemon(boolean b):参数设置为true,将线程设置为守护线程
isDaemon():判断一个线程是否是守护线程
线程安全
主要是解决多个线程的不确定性引起执行结果的不稳定
常问:
sleep()和wait(),一旦执行,使得当前线程进入阻塞状态。
sleep()和wait()区别
- 所在类不同: sleep()是Thread类的静态方法;wait()是Object类的方法
- 锁释放不同: sleep()是不释放锁的;wait()是释放锁的
- 用法不同: sleep()方法睡眠指定时间之后,线程会自动苏醒
- wait()方法被调用后,可以通过notify()或notifyAll()来唤醒wait的线程
- 使用场景不同:sleep()可在任意场景下使用,wait()必须在同步代码块或同步方法中使用
run()和start()区别
- start方法用来启动相应的线程;
- run方法只是thread的一个普通方法,在主线程里执行;
- 需要并行处理的代码放在run方法中,start方法启动线程后自动调用run方法;
反射
反射技术的源头就是Class对象。
反射概念
在class文件运行过程中,动态获取类中的内容(方法、属性等),可以进行改变,将其扩展性提高。
**注意:**任意类型包括基本类型以及void都有对应的Class 对象。
获取Class对象的方式
- 对象.getClass();
- 类名.class;
- Class.forName(“全类名”);
暴力反射: setAccessible(true)
JDK1.8新特性
list转String用 String.join()
String转list 用 Collections.addAll()
允许接口中定义带有方法体的方法
1.默认方法: 使用default修饰的
2. 静态方法: 使用static修饰的
1.Lambda表达式
对特殊形式的匿名内部类(接口)的简写
前提:接口中有且只有一个抽象方法。
格式: (参数列表) -> {执行语句;…};
Lambda表达式箭头左侧的参数列表:参数类型可以省略,只有一个参数小括号也可以省略。Lambda表达式箭头右侧:有且只有一条语句,包括return,可以将大括号和return省略。
应用于手机号码格式验证
2.函数式接口
特点:有且只有一个抽象方法的接口。
接口与有 有没有其他默认方法或静态方法无关。
通过注解@FunctionalInterface来验证
3.方法引用
可认为是Lambda表达式的另外一种表现形式
格式:
对象 :: 实例方法
类名 :: 静态方法
规则:接口中的方法的参数列表和返回值类型与引用的方法的参数列表和回值类型要保证一致,才可以使用。
构造方法引用:类名 :: new
规则:接口中的方法的参数列表 与 引用的构造方法的参数列表一致即可
4.StreamAPI
对数组或集合中的数据进行想要的计算,得到一个新的结果集,对数据源中的数据没做改变。
特点:惰性求值,只有遇到终止操作,才会进行计算,否则不计算。
步骤:
- 获取Stream对象
集合中提供的stream()方法
数组工具类中提供的stream()方法
String用 Stream类中提供的of()方法
Map集合必须将双列集合转为单列集合后,通过stream()方法获取
keySet().stream()
entrySet().stream()
values().stream() - 想要的计算(中间操作,可以有多个操作)
filter(Predicate pre): 过滤方法,通过pre返回的结果决定是否过滤
distinct():去重,去除相同的元素
limit(count):返回值指定个数的结果
skip(count): 跳过count个结果
map(Function fun) :按照fun将每个元素进行想要的计算
sorted(): 按照自然顺序排序
sorted(Comparator) : 按照比较器进行排序 - 终止操作
foreach(Consumer)
count() :统计结果集个数
collect(Collector):收集