java高阶-并发编程知识点-大杂烩(二)

4 JVM

Java Virtual Machine: 翻译工作,可以跨平台。狭义上指的就 HotSpot(JVM有很多版本,但是使用最多的是HotSpot)

  • jvm识别.class后缀文件(翻译,系统不能识别.class文件)
  • 解析文件中指令 (翻译)
  • 调用操作系统上的函数(windows、linux、macos)
  • 注意:JVM只识别字节码,与语言无关,解耦。(Java、Groovy 、Kotlin、Jruby等等语言都可以编译成字节码)

释义

  • **流程:**java程序(javac编译)-----java字节码-----JVM(Java类加载器->运行时数据区->执行引擎)-------操作系统函数(linux/windows/macos)
  • JRE(Java Runtime Environment):运行时环境,包含JVM,提供了其他类库(比如操作文件,连接网络,使用I/O等)。
  • JDK:供了一些小工具,比如 javac(编译代码)、java、jar (打包代码)、javap(反编译<反汇编>)等

运行时数据区:自动内存管理机制

  • 线程私有

    • 虚拟机栈:存储当前线程运行方法所需的数据,指令、返回地址。虚拟机栈是基于线程,生命周期跟随线程。栈里的每条数据,就是栈帧。

      栈帧/大小限制(- Xss)

    • 本地方法栈: 虚拟机栈用于管理 Java 函数的调用,而本地方法栈则用于管理本地方法的调用(由 C 语言实现)。HotSpot直接把本地方法栈虚拟机栈合二为一

    • 程序计数器 :较小的内存空间,JVM中唯一不会OOM(OutOfMemory)的内存区域。主要用来记录各个线程执行的字节码的地址,例如,分支、循环、跳转、异常、线程恢复等都依赖于计数器。(作用:时间片轮转应用。记录执行到哪一行标志)

  • 线程共享

    • 方法区/永久代 :存放已被虚拟机加载的类相关信息,包括类信息、静态变量、常量、运行时常量池、字符串常量池

    • :JVM 上最大的内存区域,申请的几乎所有对象,都是在这里存储。垃圾回收,操作的对象就是堆。需要不定期回收, GC(Garbage Collection

java堆的大小参数设置 (例如- Xmx256m)

  • -Xms:堆的最小值;
  • -Xmx:堆的最大值;
  • -Xmn:新生代的大小;
  • -XX:NewSize;新生代最小值;
  • -XX:MaxNewSize:新生代最大值;

Java平台,标准版工具参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

栈帧:都包含四个区域

  • 局部变量表:存放局部变量的,Java的八大基础数据类型、Object对象(存放其引用地址
  • 操作数栈:方法执行的操作数,操作的的元素可以是任意的java数据类型
  • 动态连接:Java语言特性多态
  • 返回地址:正常返回(调用程序计数器中的地址作为返回)、异常的话(通过异常处理器表<非栈帧中的>来确定)

class类加载:加载、验证、准备、解析、初始化

java方法开始执行:入栈

java方法执行完毕:出栈

一个方法就是一个栈帧

javap命令行: javap -c (堆代码进行反汇编)

jps:查看进程 (JVMStack)

HSDB:HotSpot Debugger

内存划分

  • 指针碰撞: 内存规律
  • 空闲列表:空位不规则
  • 并发
    • CAS失败重试
    • TLAB 本地线程分配缓存,使用线程本地分配块

Object

  • finalize() : 优先级低,需要等待; 只执行一次。 ===>try finally

可达性分析算法

对象引用

  • 强引用:
  • 软引用( SoftReference):oom时,才会回收。
  • 弱引用(WeakReference):gc时,就会回收。 eg:threadLocal
  • 虚引用:

栈跟随线程存在:线程结束,栈内存也结束(如方法栈,局部变量)

阈值

阀值

新生代: 对象朝生夕死

  • 复制算法:高效,利用率只有一半

老年代:经过多次垃圾回收,依然存在。越来越难回收

  • 标记清除算法:标记可回收/不可回收/未分配。 特点:效率不稳定, 内存碎片导致提前GC (内存不是连续的,分配内存时需要连续)
  • 标记整理算法:在清除算法的基础上,对象移动,把空闲内存移在一起。(效率低,没有内存碎片)

JVM常见垃圾收集器:

  • 单线程垃圾收集器:serial /serial Old
  • 多线程并行垃圾收集器:ParNew/Paralel Scavenge/ Parallel Old
  • 多线程并发来记收集器: CMS(清除)/ G1(整理)

CMS:concurrent mark sweep, 老年代,标记清除算法。

5.序列化

概念:将数据结构或对象转化为二进制串的过程

序列化方案:

  • serializable (externalizable,类似parcelable)
  • parcelable (android独有)
  • json/xml/protbuf

serializable

  • serialVersionUID作用:通常是个哈希码,用于对象版本控制
  • 不指定serialVersionUID(会有一个默认值):类中字段发生变更,已序列化的数据无法恢复。(新UID和旧UID不同–>InvalidClassException)
  • transient:瞬态变量,字段不会被序列化。
  • 序列化类中的引用类也必须序列化。

serializable与parcelable比较

  • serializable通过io对硬盘操作,速度慢; parcelable在内存中操作,速度快。
  • serializable大小不受限制; parcelable一般不超过1M。
  • serializable大量使用反射,产生内存碎片。

6.json

**描述:**一种轻量级的数据交换格式。

gson/fastjson

gson

  • @serializable:注解,转化key
  • @Expose:是否参与序列化/反序列化
  • 自定义TypeAdapter/自定义JsonDeserializer:解决解析异常

Gson原理

  • 反射创建该类的对象
  • 把json中对应的值赋值给对象属性
  • 返回对象。

基于事件驱动解析:边读边解析。(区别于一次性读到内存中解析)

JsonElement子类

  • JsonArray
  • JsonNull
  • JsonObject
  • JsonPrimitive: java的基本类型

TpyeToken

**适配器模式:**eg 电源转换器

TypeAdapter: json串 <------> type

  • 基本数据类型子类
  • ReflectiveTypeAdapter

7.RxJava

响应式编程: 起点—步骤一-----步骤二(一的参数)------步骤三(二的参数)----> 终点 (不间断)

被观察者(observable)-------> 观察者(observer)

核心思想: 从起点开始,将事件流向终点。可以对事件拦截/改变,下一个拦截只关联上一个拦截。

应用场景

  • rxjava配合retrofit
  • 防抖(RxHandler)
  • 网络嵌套
  • doOnNext

Rxjava方法:

  • map(new Function)

  • flatMap(new Function)

  • subscribeOn(…) / observeOn(…)

  • doOnNext(new Consumer)

  • subscribe(new Observer())

事件执行中(如网络请求中),关闭页面: onDestroy中要销毁 disposable.dispose() (onSubscribe(Disposable d))

  • 标准观察者模式

    被观察者(拥有集合容器管理观察者) ---- 多个观察者

  • RxJava的观察者模式

    多个被观察者(create/map等创建多个Observable), 一个观察者

    中间有一个抽象层(发射器,转换,onNext),降低耦合度。 (中间层装"包裹",再拆"包裹",包裹嵌套)

Hook:钩子,在流程执行中,插入新的执行。

RxJavaPlugins.setIoSchedulerHandler(new Function<Scheduler, Scheduler>() {
  @Override
  public Scheduler apply(Scheduler scheduler) throws Exception {
    Log.i("xxx","全局监听  scheduler:"+ scheduler);
    return scheduler;
  }
});

**线程切换:**最终都是交给线程池管理

  • subscribeOn: 给上面的代码分配线线程

  • observeOn: 给下面的代码分配线程

  • 线程类型

    • Schedulers.io():重用空闲的线程,比newThread效率更高。
    • Schedulers.newThread():
    • Schedulers.single()
    • AndroidSchedulers.mainThread():android主线程

8.IO

8.1 装饰模式 (功能增强)

装饰模式: 层层包裹增强

DataOutputStream out = new DataOutputStream( //基本类型数据的输出
    new BufferedOutputStream( //具备缓存功能
        new FileOutputStream( //向文件中写入数据
            new File(file)));

Component(抽象接口)

  • ConcreateComponent:具体的构建对象,实现某个功能
  • Decorator: 所有装饰器的抽象父类,继承并持有抽象接口
    • concreateDecoratorA :实际的装饰对象,实现具体的功能 (可以传入 ConcreateComponent对象)
    • concreateDecoratorB :实际的装饰对象,实现具体的功能

InputStream (抽象接口, read方法需要子类具体实现)

  • ByteArrayInputStream (具体的组件对象)

  • PipedInputStream (具体的组件对象)

  • FilterInputStream <==== 装饰器的抽象父类 (仅仅增加构造函数,持有InputStream

    • BufferedInputStream <===实际的装饰器对象

      byte[1024],一次性读取1024个字节(在调用磁盘一次读;否则一个字节读一次磁盘。)

    • DataInputStream <===实际的装饰器对象

  • FileInputStream

    File/ FileDescriptor

  • ObjectInputStream

File file = new File("/xx/xx.txt");
//嵌套流对象
DataInputStream dataInputStream = new DataInputStream(
  new BufferedInputStream(
    new FileInputStream(file)
  ));
boolean b = dataInputStream.readBoolean();
byte b1 = dataInputStream.readByte();
  • 字节流:inputStream/outputStream 字节流中的也就是一个字节符号

  • 字符流:Reader/Writer. readLine()

8.2 字符流:Reader/Writer

一个字符占用两个字节

//字节流 转换为 字符流
BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(dataInputStream));
String str = "";
while ((str = bufferedReader.readLine()) != null){ <===============行的概念
  System.out.println(str);
}

FileWriter 继承 OutputStreamWriter 依赖 FileOutputStream 依赖 File

  • 构造方法:OutputStreamWriter(OutputStream out);
  • 构造方法:OutputStreamWriter(OutputStream out,String CharSetName);
BufferedWriter out=new BufferedWriter(new OutputStreamWriter(System.out)); 
BufferedReader in= new BufferedReader(new InputStreamReader(System.in);
String line=in.readLine();

8.3 BufferedInputStream

  • 缓冲区的输入流,默认缓冲区大小是8M减少访问磁盘的次数

  • BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file));
    byte[] b = new byte[1024];
    while (bin.read(b, 0, b.length) != -1){
    	String s = new String(b);
    }
    

8.4 RandomAccessFile (随机位置文件访问)

  • 从指定位置开始读,seek(起始位置)

  • 网络数据下载应用:断点续传(分段 进行进行读)

    带宽不变的情况下,多线程分段下载能提高性能

  • 既可以读也可以写。

RandomAccessFile rsfWriter = new RandomAccessFile(file, "rw");
//从10001开始存
rsfWriter.seek(10000);

8.5 FileChannel (NIO 管道)

  • 配合ByteBuffer,操作速度更快

  • 批量/缓存的方式read/write

  • FileInputStream inputStream;
    RandomAccessFile randomAccessFile;
    FileChannel channel1 = randomAccessFile.getChannel(); //获取FileChannel
    FileChannel channel = inputStream.getChannel();//获取FileChannel
    
  • 效率 ≈ (Stream以byte数组方式)

Instant begin = Instant.now(); 
RandomAccessFile randomAccessSourceFile = new RandomAccessFile(sourceFile, "r");
RandomAccessFile randomAccessTargetFile = new RandomAccessFile(targetFile, "rw"); 
FileChannel sourceFileChannel = randomAccessSourceFile.getChannel();
FileChannel targetFileChannel = randomAccessTargetFile.getChannel();
//ByteBuffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024*1024);
while(sourceFileChannel.read(byteBuffer) != -1) {
    byteBuffer.flip();
    targetFileChannel.write(byteBuffer);
    byteBuffer.clear();
}
System.out.println("use time: " + Duration.between(begin, Instant.now()).toMillis());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值