微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

装逼就要打基础自己总结面试题-持续更新

装逼就要打基础之面试题:

Java基础

一个iterable 实现一个随机序列生产器

public class RandomStringGenerator<T> implements Iterable<T> {
    private List<T> list;
    public RandomStringGenerator(List<T> list){
        this.list = list;
    }
    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            @Override
            public boolean hasNext() {
                return true;
            }
            @Override
            public T next() {
                return list.get((int) (list.size() * Math.random()));
            }
        };
    }
    public static void main(String[] args) {
        var list = Arrays.asList("list","tree","table");
        var gen = new RandomStringGenerator<String>(list);
        for (var s :gen)
            System.out.println(s);
//        var it = gen.iterator();
//        for (int i = 0; i < 100; i++) {
//            System.out.println(it.next());
//        }
    }
}

Treeset不支持null

Map的本质时映射,kv

hashmap 哈希表实现的map

TreeSet 树实现的集合,set不支持null的容器

什么是流?

:: 运算符的作用?

Java8 Stream价值是什么?

创建Stream有几种方法?

coding: 利用parallel并发执行任务?

== 和 equals

== 在引用数据类型中是地址比较,

在基本数据类型中是值比较,

equals只能比较引用类型,是值比较,在基本数据类型的包装类中比较的是地址(重写equals方法

Buffer的原理和使用场景+面试题解读

流:随着时间到来的数据。

缓冲区:缓冲数据,请求太多…

缓冲的本质是排队,流的本质是数据。

没有缓冲:只能拒绝服务,性能

有缓冲:排队处理,批量处理(批量处理请求避免拒绝服务,批量写入磁盘快过多次写入,批量执行sql快过多次执行)

Device->Kernel Space->User Space(buffer) ->Thread

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iaa907H7-1622200361767)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210429094327231.png)]

IO的成本很高3次拷贝

缓冲区是不是流?

  • 不是,流是数据,缓冲区是缓冲数据。

缓冲区操作的几种含义:filp/rewind/clear?(Position,Limit,Capacity)

  • 当想缓冲区放入数据时,每放一个P指针会指向下一个空间,当要读取数据时,要进行翻转(flip)操作,重读或重写用rewind操作,清空缓冲区用clear操作

  • 翻转filp操作[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sScdKoi0-1622200361773)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210429100051811.png)]

  • clear操作[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZayaqLj-1622200361775)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210429100216582.png)]

  • rewind操作[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ReqjlJQL-1622200361777)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210429100127873.png)]

缓冲区设置多大?

  • 根据不同的系统对应设置的缓冲区的大小也不应该一样,buffer大小一般不需要自己设置,认8192 ,
  • 根据不同的业务设置缓冲区,再进行批量处理。

NIO的Channel比缓冲区快么?

  • 如果都用了buffer手段,nio不是更快,只不过是提供了更标准化的操作。只需要记住缓冲区的操作。

缓冲过程中,中文乱码如何处理?

并发分析数据更快么?

计算一个文件的词频?

MysqL

索引

就是帮助MysqL高效获取数据的排好序的数据结构

底层实现 B+树 双向指针[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4OsHMcgb-1622200361780)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210523110604786.png)]

红黑树:平衡二叉树

哈希索引

算出key的hash值,存地址。

不适合范围查询

B树[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JjWGT5Vc-1622200361781)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210523110451169.png)]

数据库表存储引擎:
修饰数据库表的

  • 表数据文件本身就是按照B+树组织的一个索引结构文件
  • 聚集索引-叶节点包含了完整的数据记录
  • 为什么建议Innodb必须建主键,并且推荐使用整形的自增主键?
    • 如果不建立主键,数据库会根据你的表里的数据自己寻找一个不重复的列作为主键,如果表里的数据没有可选的主键,数据库会自己维护一个rowid来作为主键,非常耗费资源,影响性能
  • 为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省储存空间)

联合索引的底层存储结构什么样?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRndy2C2-1622200361782)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210524084605757.png)]

索引最左前缀原理

为什么使用主键自增而不是uuid?
uuid是字符串,主键自增
插入可以更快减少比较和移动.

当查的字段类型不匹配时会转型,int的字符串会转为0

索引失效:对字段进行操作

Buffer Pool

空间 128M 有三个链表

  • free链表 存空位置的
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gM0GMBnF-1622200361782)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210524210359626.png)]

  • flush链表 存脏页
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lsPp92vw-1622200361783)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210525080412131.png)]

  • LRU链表 热数据:冷数据 = 5:3
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-36zv6y1f-1622200361784)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210525083055042.png)]

update
更新buffer pool里面的页数据
生成redoLog,commit之后持久化redoLog,顺序IO
即使数据库挂了,也可以通过redoLog还原数据redolog文件一开始就开辟48M的空间

两个redolog文件都有checkpoint到达这个点就要持久化 ,redolog文件先存在logbuffer, redolog是innodb层面的

随机IO费时

binlogMysqL层面的用于给其他从数据库数据

undolog还原用记录之前

doublewritebuffer innodb持久化时16->4需要判断能不能写成功

面试题

索引的原理

把无序的数据建立有序的查询

  • 把创建了索引的列的内容进行排序
  • 对排序结果生成倒排表
  • 在倒排表内容上拼上数据地址链
  • 查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

聚簇索引和非聚簇索引

聚簇索引:数据和索引在一起,而且有排序

非聚簇索引:叶子节点存储的不是数据,是地址

innoDB中一定有主键,主键一定是聚簇索引,不手动设置会使用唯一索引,没有唯一索引会自己生成一个rowid

MyISM使用的是非聚簇索引,没有聚簇索引,存储的内容不一样

索引的数据结构

B+树:一般时候

Hash:单条记录查询

索引设计的原则

查询更快,占用空间更小

  • 需要在where中出现,或者连接某一个
  • 基数比较小表,索引效果差,没必要建立索引
  • 使用短索引
  • 不要过度索引
  • 定义有外键,一定要建立索引

musql锁的类型有哪些

属性分类共享锁,排他锁

粒度分类:行级锁,表级锁,页级所,记录锁,间隙锁,临键锁

状态分类:意向共享锁,意向排他锁

  • 共享锁

    共享锁就是读锁,S锁,当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重读的问题。
    
  • 排他锁

    排他锁又称为写锁,X锁,当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改时,不允许其他人同时修改,也不能读。避免脏读,脏数据
    
  • 表锁

    整个表,粒度大,加锁简单,但是容易冲突   myISM
    
  • 行锁

    可以多行,粒度小,不容易冲突,并发比表锁高  innodb
    
  • 记录锁

    记录锁是行锁的一种,只查一条记录,命中条件字段是唯一索引。
    
  • 页锁

    介于表锁和行锁之间,
    
  • 间隙锁

    左开右闭
    
  • 临建锁

    记录锁和间隙锁的组合
    
  • 意向共享锁

    一个事务试图对整个表进行加共享锁之前,首先需要获得这个表的意向共享锁
    
  • 意向排他锁

    一个事务试图对整个表进行加排他锁之前,首先需要获得这个表的意向排他锁
    

执行计划

explain

执行效率:

ALL<inde<range<ref<eq_ref<counst<system.最好避免ALL和index

事务的基本特性 ACID

原子性 一起成功,一起失败

一致性 一致性关注数据的可见性,中间状态的数据对外部不可见,只有最初状态和最终状态的数据对外可见

隔离性 一个事务在最终提交前,对其他事务是不可见的

持久性 事务提交,所做的修改就会永久保存到数据库中。

ACID靠什么保证的

A原子性由undolog日志保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行的sql

C一致性由其他三大特性保证、程序代码也要保证业务上的一致性

I隔离性由MVCC来保证

D持久性 由内存+redolog来保证,MysqL修改数据同时在内存和redolog记录这次操作,宕机也可以从redolog恢复

InnoDB redolog写盘,InnoDB事务进入prepare状态。如果prepare成功,binlog写盘,再继续将事务日志持久化到binlog,如果持久化成功,那么InnoDB事务则进入commit状态(就是在redolog里面写一个commit记录)

隔离性有四个隔离级别

sql 标准定义了四种隔离级别,MysqL 全都支持。这四种隔离级别分别是:

  1. 读未提交(READ UNCOMMITTED)

  2. 读提交 (READ COMMITTED Oracle mvcc)

  3. 可重复读 (REPEATABLE READ MysqL mvcc)

  4. 串行化 (SERIALIZABLE)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xXqvGcZc-1622200361785)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210525164511145.png)]

MysqL 的 InnoDB 引擎才支持事务,其中可重复读是认的隔离级别。

读未提交和串行化基本上是不需要考虑的隔离级别,前者不加锁限制,后者相当于单线程执行,效率太差。

读提交解决了脏读问题,行锁解决了并发更新的问题。并且 MysqL 在可重复读级别解决了幻读问题,是通过行锁和间隙锁的组合 Next-Key 锁实现的。

MVCC

多版本并发控制:它的实现原理主要是版本链,undo日志 ,Read View 来实现的

mvcc只在 rc rr

从以上的描述中我们可以看出来,所谓的MVCC指的就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的SEELCT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能

版本链

除了数据 以外分别是db_trx_id、db_roll_pointer、db_row_id。

对该记录每次更新后,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。另外,每个版本中还包含生成该版本时对应的事务id,这个信息很重要,在根据ReadView判断版本可见性的时候会用到。

查询

看看查询条件有没有命中索引,是不是加载了不需要的数据列,分析语句执行计划,如果只是因为数据量太大,就可以考虑横向或者纵向分表

分库分表

shardingSphere和shardingProxy

MysqL主从同步

MysqL 主从复制模式:

异步模式(MysqL async-mode)

全同步模式

半同步

MyISAM 和 InnoDB的区别

MyISAM:

  • 不支持事务,但是每次查询都是原子的

  • 表级锁,维护了一个总行数;

  • MyISAM表有三个文件:索引文件、表结构文件、数据文件

  • 采用非聚簇索引,索引文件的数据域存储指向数据文件指针。辅索引与主索引基本一致,但是副索引不用保证唯一性。

InnoDB:

  • 支持ACID的事务,支持事务的四种隔离级别;

  • 支持行级锁外键约束:因此可以支持写并发;

  • 不存储总行数;

  • InnoDB引擎存储在一个文件空间(共享表空间,表大小不受操作系统控制,一个表可能分布在多个文件里),也有可能为多个(设置独立表空间,表的大小受操作系统文件大小限制,一般为2G)受操作系统文件大小的限制;

  • 主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要通过辅索引找到主键值,再访问辅索引;最好用主键自增,防止插入数据时,为维持B+树结构而调整

  • MyISAM 存储引擎 非聚集索引
    三个文件: 表结构.frm 存储引擎数据.MYD 存储引擎索引.MYI 需要回表

  • Innodb 存储引擎 聚集索引
    两个文件: 表结构.frm 存储引擎数据,索引 .ibd

  • innodb引擎的4大特性
    插入缓冲(insert buffer),二次写(double write),
    自适应哈希索引(ahi),预读(read ahead)

索引类型对性能影响

普通索引:允许被索引的数据列包含重复的值。

唯一索引:可以保证数据记录的唯一性

主键:是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字primarykey来矿建

联合索引:索引可以覆盖多个数据列,就是多个列

全文索引:通过建立倒排索引,可以极大的提升检索效率,解决判断字段是否包含的问题,是目前搜索引擎使用的一种关键技术。可以通过ALTER TABLE tablename add fulltext,创建全文索引,但是比较鸡肋,现在都用ElastictSearch

索引可以极大的提高数据的查询速度。

通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能

但是会降低插入,删除,更新表的速度,因为在执行这些写操作时,还要操作索引文件

索引需要占用物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大,如果非聚簇索引很多,一旦聚集索引改变,那么所有非聚簇索引都会跟着变。

数据结构与算法

排序本质就是进步的方式,进步就是无序到有序,有三种:加一减一法,分治策略,哈希函数(将无需映射成有序)

插入排序:

for(int i = 1; i < A.length; i++) {
    // 将A[i] 插入在卡片0,到卡片i之间
    // j代表抓到的牌,先放到最右侧,不断交换到对应的位置

    int c = A[i];
    int j = i;

    for(; j > 0 && A[j-1] > c;j--) {
        A[j] = A[j-1];
    }
    A[j] = c;

选择排序:从后往前遍历可以保证稳定性

for(int i = A.length - 1; i >= 0; i--) {
    
    // 0 - A[i]
    int j = maxIndex(A, 0, i+1);
    Helper.swap(A, i, j);
}
//不稳定 选择排序比插入排序写少
static private int maxIndex(int[] A, int i, int j) {
    int max = Integer.MIN_VALUE;

    int maxIndex = j-1;
    for(int k = i; k < j; k++) {
        if(max < A[k]) {
            max = A[k];
            maxIndex = k;
        }
    }
    return maxIndex;
}
//稳定
static private int maxIndex(int[] A, int i, int j) {
    int max = Integer.MIN_VALUE;

    int maxIndex = j-1;
    for(int k = j-1; k >= i; k--) {
        if(max < A[k]) {
            max = A[k];
            maxIndex = k;
        }
    }
    return maxIndex;
}

递归不终止StackOverflow(在栈上不停的push元素)

内存读取cpu缓存很快 ,写不能只写缓存

分治策略(Divide And Conquer):

 public void sort(int[] A) {
     mergeSort(A, 0, A.length);
 }
private void mergeSort(int[] A, int l, int r) {
    if(r - l <= 1) {
        return;
    }
    int mid = (l+r+1)/2;
    mergeSort(A, l, mid);
    mergeSort(A, mid, r);
    merge(A, l, mid, r);
}
private void merge(int[] A, int l, int mid, int r) {
    int[] B = Arrays.copyOfRange(A, l, mid+1);
    int[] C = Arrays.copyOfRange(A, mid, r+1);
    B[B.length-1] = C[C.length - 1] = Integer.MAX_VALUE;
    int i = 0, j = 0;
    for(int k = l; k < r; k++) {
        if(B[i] < C[j]) {
            A[k] = B[i++];
        } else {
            A[k] = C[j++];
        }
    }

合并排序设置哨兵

copyOfRange超出会补零

快速排序归纳:

流式编程

public List<Integer> sort(List<Integer> A) {
    return this.quickSort(A);
}
private List<Integer> quickSort(List<Integer> A) {
    if(A.size() <= 1) {
        return A;
    }
    // |---left---| x | ---right ---||
    var x = A.get(0);
    var left = A.stream().filter(a -> a < x)
        .collect(toList());
    var mid = A.stream().filter(a -> a == x)
        .collect(toList());
    var right = A.stream().filter(a -> a > x)
        .collect(toList());
    left = quickSort(left);
    right = quickSort(right);
    left.addAll(mid);
    left.addAll(right);
    return left;
}

实现 IMutableSorter

public void sort(int[] A) {
    this.quickSort(A, 0, A.length);
}

private void quickSort(int[] A, int l, int r) {
    if(r - l <= 1) {
        return;
    }
    // 选择最左边的元素构造子问题集合
    // 小于x的放到左边,大于x的放到右边
    // int x = A[l];
    // i代表x的位置
    int i = partition(A, l, r);
    // 省略计算x所在位置i
    // 以及将所有小于x的元素放到左边,大于x元素放到右边的
    quickSort(A, l, i);
    quickSort(A, i+1, r);
}
private int partition(int[] A, int l, int r) {
    int x = A[l];
    int i = l + 1;
    int j = r;
    while(i != j) {
        if(A[i] < x) {
            i++;
        } else {
            Helper.swap(A, i, --j);
        }
    }
    Helper.swap(A, i-1, l);
    return i-1;
}

桶排序要求对数据有了解

Coding:链表的表示?

static class Node<T> {
    Node<T> next = null;
    T data;
    public Node(T data){
        this.data = data;
    }
}
Node<T> head = null;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OE7mISgQ-1622200361786)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210502100001112.png)]

Coding:增删改查? 相关复杂度?

// O(1) 头插法
    public void insert(T data) {
        var node = new Node<>(data);
        node.next = head;
        head = node;
    }

    // O(n) 查询用断言
    public Node<T> find(Predicate<T> predicate) {
        var p = head;
        while(p != null) {
            if(predicate.test(p.data)) {
                return p;
            }
            p = p.next;
        }
        return null;

    }

    public Integer size(){
        var p = head;
        Integer c = 0;
        while(p != null) { p = p.next; c++; }
        return c;
    }

    // O(n) 
    public void remove(Node<T> node){
        if(head == null) {
            return;
        }

        if(head == node) {
            head = head.next;
            return;
        }

        var slow = head;
        var fast = head.next;

        while(fast != node && fast != null) {
            slow = fast;
            fast = fast.next;
        }
        if(fast != null) {
            slow.next = fast.next;
//            fast.data = null; //删除时可以考虑回收问题,释放资源,data比较大
        }
    }

Coding:合并两个链表的操作? 用哨兵

翻转链表:三指针,递归

实现队列,栈?

Coding:判断链表中是否有环?

快慢指针是否相等

Coding:和CAS Loop结合?

HashTable的原理?

存取映射的数据结构

一个Hash函数? 取余

Java的HashMap怎么实现的?

除了哈希表还有那些适合存Key/Value的数据结构?

ConcurrentHashMap是怎么回事?什么时候用?

两次hash

JavaObject的HashCode是如何计算的?

集合框架

集合的概念

集合的概念

  • 对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能

集合和数组的区别

  • 数组长度固定,集合不固定
  • 数组可以存储基本数据类型和引用数据类型,但是集合只能存储引用数据类型

集合的位置

  • Java.util.*

Collection接口

List和Set接口都实现了Collection接口,Collection接口的体系如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4l4u6kUW-1622200361787)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210509093854188.png)]

Collection特点

  • 代表一组任意类型的对象,无序,无下表,不能重复

Collection方法

返回值类型方法作用及描述
booleanadd(E e) 确保此集合包含指定的元素(可选操作)。
booleanaddAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合(可选操作)。
voidclear() 从此集合中删除所有元素(可选操作)。
booleancontains(Object o) 如果此集合包含指定的元素,则返回 true
booleancontainsAll(Collection<?> c) 如果此集合包含指定 集合中的所有元素,则返回true。
booleanequals(Object o) 将指定的对象与此集合进行比较以获得相等性
inthashCode() 返回此集合的哈希码值。
booleanisEmpty() 如果此集合不包含元素,则返回 true
Iterator<E>iterator() 返回此集合中的元素的迭代器。
default Stream<E>parallelStream() 返回可能并行的 Stream与此集合作为其来源。
booleanremove(Object o) 从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
booleanremoveAll(Collection<?> c) 删除指定集合中包含的所有此集合的元素(可选操作)。
default booleanremoveIf(Predicate<? super E> filter) 删除满足给定谓词的此集合的所有元素。
booleanretainAll(Collection<?> c) 仅保留此集合中包含在指定集合中的元素(可选操作)。
intsize() 返回此集合中的元素数。
default Spliterator<E>spliterator() 创建一个Spliterator在这个集合中的元素。
default Stream<E>stream() 返回以此集合作为源的顺序 Stream
Object[]toArray() 返回一个包含此集合中所有元素的数组。

List接口与实现类

List特点

  • 有序、有下标、可以重复

List方法

  • voidadd(int index, Object o) 在第index位置插入
    booleanaddAll(int index, Collection c) 将指定集合中的所有元素插入到此列表中的指定位置
    Objectget(int index) 返回此列表中指定位置的元素。
    ListsubList(int fromIndex,int toIndex) 返回fromIndex (含)和 toIndex间的集合元素
    ListIterator<E>listIterator(int index) 从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器,既可以从前往后也可以从后往前。
    booleanremove(Object o) 删除指定元素的第一个出现,传index可以删除第几个。
    Eset(int index, E element) 用指定的元素修改

ArrayList

  • 数组实现,查询快,增删慢
  • 运行效率快,但是线程不安全
  • 当集合中有元素时认大小10,当集合中没有元素时大小为0,扩容(每次的容量+容量右移一位)1.5

Vector

  • 数组实现,查询快,增删慢
  • 运行效率慢,线程安全
  • 和ArrayList相似 有枚举器

LinkedList

  • 双向链表结构实现,增删快,查询慢 双向链表
  • 有枚举器

LinkedList 和 ArrayList区别

ArrayList必须开辟连续的空间,查询快,增删慢

LinkedList 不需要开辟连续的空间,查询慢,增删快

Set接口与实现类

Set接口特点

  • 无序、无下标、元素不可重复

Set接口方法

  • 全部继承了Collection的方法

HashSet

  • 存储结构:哈希表 (之前是 数组+链表 ,1.8之后 数组+链表+红黑树)就是HashMap只存key
  • 基于Hashcode计算元素存放的位置
  • 当存入元素的哈希码相同时,调用equals进行确认,如结果为true,则拒绝存入
  • 重写hashcode 时 +31,31是一个质数,减少散列冲突、提高执行效率hashcode+31 * i = (i << 5) -i

TreeSet

  • 基于排列顺序实现元素不重复
  • 实现了SortedSet接口,对集合元素自动排序
  • 元素对象的类型必须实现Comparable接口,指定排序规则
  • Compareto检测是否为重复元素
  • 可以重写 Compareto
  • 用的就是TreeMap的key

Map接口与实现类

Map

  • 存储一对数据(Key-Value)、无序、无下标、键不可重复、值可以重复

  • 遍历方式:

    • 遍历用keyset先获取key,再通过map.get()获取value

    • 还可以使用entrySet() Set<Map.Entry<K,V>> entrys = map.entrySet() 返回此地图中包含的映射的Set视图。

      通过for遍历出所有单个的entry,再entry.getkey()entry.getvalue()

Vput(K key, V value) 将指定的值与该映射中的指定键相关联
Vget(Object key) 返回到指定键所映射的值,或 null如果此映射包含该键的映射。
Set<Map.Entry<K,V>>entrySet() 返回此地图中包含的映射的Set视图。
Collection<V>values() 返回此地图中包含的值的Collection视图。
Set<K>keySet() 返回此地图中包含的键的Set视图。

HashMap

  • 线程不安全,运行效率快,允许null作为key或者value
  • hashmap刚创建table是null,为了节省空间,在第一次插入容量调整为16,加载因子0.75,扩容容量左移一位,目的是减少调整元素的个数
  • 存储结构(数组链表红黑树)
  • 1.8后当每个链表的长度大于8时,并且数组元素个数大于等于64,自动转为红黑树,提高效率
  • 1.8后当链表长度小于6时,自动转为链表
  • 1.8以前,链表是头插法,之后是尾插法

TreeMap

  • 存储结构:红黑树
  • 操作时要实现comparable接口

HashTable

  • 线程安全,运行效率慢,不允许null作为key或者value
  • 初始容量11

properties

  • HashTable的子类要求key和value都是String。常用于配置文件的读取

collection常用工具方法

copy 复制 Collection的需要的空间要提前创建好

reserse翻转

shuffle 打乱

list.toArray()

Array.asList()

多线程

进程线程

进程和线程的区别?

  • 进程是程序执行的副本,线程是轻量级的进程,线程是并发(concorrent)的模型,一个进程里可以有很多个线程,线程共享整个进程的资源

为什么要有线程?

  • 线程(Thread)还被称为是轻量级的进程。

为什么要减少线程切换?

  • 因为有可能产生ABA问题

进程开销为什么比线程大?

  • 因为进程有资源,线程只有计算的能力。

JAVA线程有哪些状态?如何转换?

  • 基本状态:

    1. 运行态(Running)
    2. 就绪态(Ready)
    3. 休眠态(Sleeping)。我们通常说的阻塞态(Blocking)是休眠态的一种情况。
  • Java特有状态:

    1. NEW 构造
    2. TERMINATED 完成
    3. RUNAABLE 对应运行态和就绪态
    4. WAITING/TIME_WAITING/BLOCKED 超时等待
  • 保存当前线程的状态(cpu寄存器的值)
    重新执行调度程序(操作系统),重新选择其他线程执行

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bcoveHd6-1622200361788)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210506162246123.png)]

ThreadLocal

  • 提供线程局部变量;一个线程局部变量在多个线程中,分别有独立的值。
  • 特点:简单(开箱即用)、快速(无额外开销)、 安全(线程安全)
  • 场景:多线程场景(资源持有、线程一致性、并发计算、线程安全等)
  • 实现原理:Java中用哈希表实现。
  • 应用范围:几乎所有提供多线程特征的语言。

排队很危险,

  • Quartz的SimpleSemaphore提供资源隔离

Java线程是内核级线程还是用户级线程?

  • 内核级线程由内核调度,用户级线程有应用自己调度。

  • jvm不调度,只维护

  • 在之前是用户级线程,后来jdk1为内核级线程,共享内核级线程分配的主线程。

  • 总结:Java采用用户-内核级线程映射(总体来说是内核级线程)

多线程和原子操作

竞争条件是怎么产生的?解决竞争条件有哪些方法

  1. 两个线程发生竞争的区域(访问共享资源i )
  • 减少竞争
  • 实现原子操作
  • TAS指令
  • 互斥

原子操作是如何实现的?

  • CAS(Compare And Swap 或者 Compare And Set)
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M2FAaH1q-1622200361789)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210506191620817.png)]
  • cas操作:比较现在expectedValue和之前expectedValue的值是否相等,如果是,更新目标值
  • 作用:设置一个地址的值
  • 约束:要求指令的使用方必须知道这个地方原来的值
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GTBdiK1J-1622200361789)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210506191755861.png)]

Java的CAS是如何实现的?

  • 底层类Unsafe jdk.internal.misc.Unsafe 给cpu指令

CAS的ABA问题是怎么回事?

  • 线程1 cas(&A, A, B)
  • 线程2 cas(&A, A, B)cas(&B, B, A)

AtomicInterger类是如何实现的?**

  • 用AtomicInterger不会发生竞争条件

  • get set 都是原子的

  • 但是自增调用Unsafe类的cas

AtomicStampedReference解决什么问题?内部如何实现?

同步器

什么是同步?

  • 执行同步
    • 多个参与方(多线程、进程)
    • 汇合(Join)
      • 例如:互相等待
    • 执行后续操作
  • 数据同步
    • 多份数据保持数据一致
      • 缓存和存储的同步
      • 不同机房订单数据的同步

简述下Java有哪些同步器?

基于Monitor JVM的实现

  • synchronized

基于AQS设计

  • Reentrant Lock
  • Read/Write Lock
  • CyclicBarrier
  • Semaphore
  • CountDownLatch

synchronized是如何实现的?

  • 依赖于Monitor JVM的实现

reentrantlock和synchronized的区别?

  • synchronized完全支持Blocking算法,reentrantlock支持Non-Blocking(可以tryLock) + 支持Timeout
  • reentrantlock比较灵活,异常处理比较快,提供了中断能力,第一时间收到中断
  • synchronized 用 等待wait( )唤醒notify( ) , reentrantlock 等待await( ) 唤醒 signal( )。

为什么需要AbstractQueuedSynchronizer?

  • Java提供的同步器开发框架
  • 需要一个框架来帮助程序员开发同步器,省的程序员在底层上浪费时间,降低心智负担

偏向锁、轻量级锁、重量级锁是怎么回事?

  • 轻量级锁用java抢占资源,重量级锁用操作系统抢占资源(开销更高)自旋锁很快,spinLock。

  • 没有资源竞争偏向锁,发生竞争就升级为轻量级锁,轻量级锁拿不到持有者权限就要升级为重量级锁。

  • 当设置偏向锁后,当资源没有持有者,可以跳过EntrySet直接参与竞争。

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sks7wWBJ-1622200361790)(C:\Users\Administrator\Desktop\笔记\JVM\屏幕截图 2021-05-07 153333-1620375868435.png)]

Java实现生产者消费者问题

Monitor 提供wait,提供notify 所有的Object都有

AbstractQueuedSynchronizer提供await,signalAll。

// Producer 生产者
public void readDb() throws InterruptedException {
    lock.lock();
    if (queue.size() == MAX) {
        full.await();
        return;
    }
    var data = readData(); // 1s
    if(queue.size() == 1) {
        emtpy.signalAll();
    }
    queue.add(data);
    lock.unlock();
}

// Comsumer 消费者
public void calculate() throws InterruptedException {

    lock.lock();
    if (queue.size() == 0) {
        emtpy.await();
        return;
    }
    var data = queue.remove();
    System.out.println("queue-size:" + queue.size());
    if(queue.size() == MAX - 1) {
        full.signalAll();
    }

    data *= 100;
    lock.unlock();
}

AQS(AbstractQueuedSynchronizer)

区别于synchronized(build-in or intrinsic lock), Java提供的另一个实现同步的体系

半壁江山synchronized 另一半AQS

AbstractQueuedSynchronizer可以用来做什么?

  • 中断(InterruptedException)
  • tryLock(int a ,TimeUnit) 超时获取
  • tryAcquire 非阻塞获取
  • acquire 和 release 阻塞获取锁,释放锁
  • Condition 条件变量封装,条件变量是os提出的,条件变量的本质也是原子操作
  • 封装CAS操作
    • acquire/release都基于cas状态
    • cas失败触发在等待队列中等待
  • 内部封装高性能CLH队列(让进入队列成本变低)
    • CAS失败自动进入休眠队列
    • 条件等待自动进入队列

简述AbstractQueuedSynchronizer如何工作?

手写程序:如何用AbstractQueuedSynchronizer实现Mutex(互斥量)?

  • 继承AQS重写tryAcquire和tryRelease 用cas()

  • 线程调用时计算前上锁,退出后解锁

  • public class Mutex extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            return compareAndSetState(0,1);
        }
        @Override
        protected boolean tryRelease(int arg) {
            return compareAndSetState(1,0);
        }
    
        public static int i = 0;
        public static void main(String[] argv) throws InterruptedException {
            var mutex = new Mutex();
            Thread t1 = new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    mutex.acquire(0);
                    i ++;
                    mutex.release(0);
                }
            });t1.start();
            Thread t2 = new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    mutex.acquire(0);
                    i ++;
                    mutex.release(0);
                }
            });t2.start();
            t1.join();
            t2.join();
            System.out.println(i);
        }
    }
    

AQS如何实现公平性?

  • reentrantlock(true)中公平锁实现了hasQueuedThreads()看有没有进程在排队,有排队的直接进入休眠队列。

CAS在AQS中的作用是什么?

  • 在进入队列时保证原子操作。
  • 为tryAcquire提供计算能力。

AQS内部的CHL算法工作原理是什么?

JVM

栈和堆的区别:

栈的作用:配合程序执行,函数调用用的,提供执行程序的必须内存空间,栈的数据结构像一个数组,因为是一个连续的数据结构,栈的内存分配是指针从高为到低位,从小地址向大地址增长

栈配合程序执行用的,配合程序方法调用,存储程序的临时数据 ,也可以存对象

一个线程都有一个栈,因为线程是程序执行的最小单位。线程可以没有堆

堆的作用:用来存储数据,通过堆来存它不是一种数据结构,是一堆数据结构。堆通过引用来引用这些结构。从小地址到大地址增长,什么都有,像一个垃圾堆。

应用通过堆存储数据(申请,回收,托管)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jjs31JHS-1622200361791)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210526203940712.png)]

JVM的内存布局:

这是从Object的角度 hotspot[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ublBgJ4B-1622200361792)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210527091249757.png)]

从线程的角度[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rTy8LDm3-1622200361793)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210527092007800.png)]

整体的架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zh7g3z9l-1622200361794)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210527092137751.png)]

JIT编译器一边执行程序,一边编译。GC执行引擎不只是垃圾回收器还是内存分配工具,来管理堆

ClassLoader将.class文件导入JVM,形成运行时的类
执行引擎执行bytecode和处理GC
执行引擎调用本地库接口,执行本地方法
本地方法执行时使用Native Stack(可能形成Native Memory)

JVM中Object都有哪些数据:

类的信息,常量,编译后的代码

JVM的运行时数据都有哪些:

Heap MethodArea Stack NativeStack ProgramCounter NativeMemory

为什么要GC?

应用在不断的弄乱空间,GC就负责整理

什么是STW?

Stop The World ,当GC忙不过来就要STW

如何提高吞吐量(Throughput)?

吞吐量: 程序执行时间的占比

-XX: GCTimeRatio=99 99:1 1%
-XX: GCTimeRatio=19 19:1 5%

  • 给更大的内存(Heap+++) -Xmx4G 最大4G Heap
  • 更改GC算法

高吞吐量、低延迟和低FootPrint,可以兼得吗? 谈谈你的理解?

低延时 Latency : 指GC造成的停顿(STW)时间

Pause Time: 一次STW的时间

FootPrint :指最终应用对内存的需求 当内存满了需要:STW回收。

引用计数法有什么问题?

循环引用

静态的 并发就不行了

为什么需要3色标记而不是双色?

双色,如果在标记和清除的中间有改动,会导致回收多了,所以这种状况就需要重新标记之后才能清楚。这时C为黑色,D,E会被清除。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cvapvfpq-1622200361796)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210527161859385.png)]

3色标记算法如何处理变化(mutation)?

当有一个不确定是否能清除时,要先进行标记标记到最后,而且没有变化时,就可以清除了。然后GC需要遍历JavaHeap中所有的对象清除没有被标记的对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iUujjGLm-1622200361797)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210527162039646.png)]

Java堆分成哪些部分[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l7cNiSpp-1622200361797)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210527164753200.png)]

新生代、存活代、老生代、永久代(元空间)是什么?如何工作的?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZJ5nUcx5-1622200361798)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210527165333878.png)]

新生代发生minorGC 有eden和 survivor from (s1) to (s2) 老年代发生fullGC(标记-清除),永久代(元空间)在方法区中。

什么时候发生复制和整理?

在新生代中 eden到survivor发生复制和整理

G1/CMS/Serial/Parallel/ParNew/ZGC的区别?

G1:目标:大内存,兼顾:Latency、Throughput,替代:CMS(尚未、部分)

ZGC:低延迟的GC 最大延迟时间几个ms 暂停时间不会随着堆大小、存活对象数目增加 内存范围8MB~16TB 太大容易挂

CMS(Concurrent Mark Sweep) :减少Pause Time,覆盖Serial/Parallel Collector的场景 ,需要减少 pause Time的场景

Parallel(并行):多线程, 提供最大的Throughput

Serial(连续的):Single Thread ,也能提供最大的Throughput

ParNew :多线程

如果对延迟要求高可以考虑哪种GC?

ZGC

内存空间很大的情况(TB)级别推荐哪种GC?

G1

类加载器有哪些

根加载器 BootStrapClassLoader

拓展加载器 ExtensionsClassLoader

程序加载器 ApplicationClassLoader

用户加载器 CustomClassLoader

说一下Object在内存中的格式?

有严格定义
不同虚拟机可能会不同
分成头部和数据,可能还有Padding

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iq86r2tI-1622200361799)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210528145553265.png)]

mark word

hashcode age 标志位 LockRecordAddress MonitorAddress ForwardingAddress

klassOop: 指向Object的元数据

padding:对齐, Hotspot:8字节对齐

说一下初始化一个类的过程?

类的生命周期大致分为以下阶段:

load
类加载 disk -> memory ClassLoader
static initializers 初始化 static fields {}
触发原因:new/访问静态成员/loader加载等
加载完毕 loaded

create
allocate memory 分配内存
constructor 构造器
created 创建完毕就

live
in use Root Set可以找到(且被使用)
invisible 泄露,Root Set可以找到,但是没有使用
unreachable Root Set不可达(会被回收)

destroy/gc
collected 要被收集
finalize 终节资源
deallocated 回收完

空的Object多大?

肯定是8的倍数 64个字节(8bit)才能存的下,最少16字节

Class Header里都有什么?

markword

klassoop

arraylength

什么是双亲委派模型?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6sX1dflu-1622200361800)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210528180504240.png)]

说说双亲委派的过程?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eqgP7mSK-1622200361801)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210528180507844.png)]

只有一个ClassLoader为什么不够用?

  • 需求不同
  • 可能存在版本问题 ,名字一样
  • 安全和缓存
  • MetaProgramming

如何打破双亲委派模型?

重写ClassLoader.loadClass()

Linux

usr unix system resouce

var variable data file

pwd 打印当前路径

more 打印一部分

less 打印一部分 有个界面

tail 尾部一行

head 头部一行

man 查看命令

cat 查看所有

tac 倒着查看所有

grep 加限定条件

find 查找

wc -l 查看文件数量

ip addr 可以查看IP地址

netstat 显示网络状态

host 查看dns

curl 开发联调工具

‘>’ 重定向

TCP/IP协议

互联网协议群:

  • 应用层
  • 传输层
  • 网络层
  • 链接
  • 物理层

发送消息如何确认收到?

握手:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lQC4eSrn-1622200361802)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210521170015876.png)]

挥手:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0p7LzHgV-1622200361803)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210521170233302.png)]

Socket、IO模型、NIO

Socket的工作原理

  • socket是一种管道文件[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aCDpIkfY-1622200361804)(C:\Users\Administrator\Desktop\笔记\JVM\image-20210521175208328.png)]

  • Server Socket File中是Client Sockets’ 的FD

    • listen(80)
    • clientsocket = serversocket.accept()
  • Client Socket中是数据

I/O多路复用

BIO/NIO/AIO

N(new)IO

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐