JAVA基础笔记(持续更新)

1、时间复杂度:
    算法函数式只保留最高阶并去掉系数即为O时间复杂度,用于衡量算法。
2、代理模式和装饰模式的区别:
    装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。
用一句话来总结这些差别:使用代理模式,代理和真实对象之间的的关系通常在编译时
就已经确定了,而装饰者能够在运行时递归地被构造。
3、关于hashtable
    键值对存储private transient Entry[] table;中,是一个Entry数组。
    其中的Entry是被重写的内部类,内部单向链表设计如下:
    // 指向的下一个Entry,即链表的下一个节点
     Entry<K,V> next;
  
    // 构造函数
    protected Entry(int hash, K key, V value, Entry<K,V> next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
     }
    实现线程安全的原因是其中put与remove方法是synchronized
    解决过多哈希碰撞演变成链表:HashMap在JDK1.8及以后的版本中,链表超过8会转换成
红黑树,小于6会换回链表。
4、ConcurrentHashMap与HashTable区别:
    同put与remove方法同步,但ConcurrentHashMap相比 HashTable而言它不是锁全部数据,
而是锁一部分数据,这样多个线程访问的时候就不会出现竞争关系。
    原理:ConcurrentHashMap主干是Segment数组。Segment分段锁功能,每一个Segment 
都相等于小的hash table并且都有自己锁,只要修改不再同一个段上就不会引起并发问题。
    ConcurrentHashMap当超过阈值时会增加链表长度而不是数组扩容。
5、volatile
    使用volatile关键字会强制将修改的值立即写入主存,当线程2进行修改时,会导致线程1
的工作内存中缓存变量的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中
对应的缓存行无效),由于线程1的工作内存中缓存变量的缓存行无效,所以线程1再次读取
变量的值时会去主存读取。
    volatile也无法保证对变量的任何操作都是原子性的。只保证多线程同时改时,缓存失效读
取主存,而不保证先读,堵塞,另一线程修改,在执行先前线程修改数据一致。
6、redis
    单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,
所以 Redis 事务的执行并不是原子性的。事务可以理解为一个打包的批量执行脚本,但批量
指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续
的指令不做。
7、MYSQL存储引擎
MyISAM
    它不支持事务,也不支持外键,尤其是访问速度快,对事务完整性没有要求或者以SELECT、
INSERT为主的应用基本都可以使用这个引擎来创建表。
InnoDB
    InnoDB是一个健壮的事务型存储引擎,引入了行级锁定和外键约束,在以下场合下,
使用InnoDB是最理想的选择:
    1.更新密集的表。InnoDB存储引擎特别适合处理多重并发的更新请求。
    2.事务。InnoDB存储引擎是支持事务的标准MySQL存储引擎。
    3.自动灾难恢复。与其它存储引擎不同,InnoDB表能够自动从灾难中恢复。
    4.外键约束。MySQL支持外键的存储引擎只有InnoDB。
    5.支持自动增加列AUTO_INCREMENT属性。
一般来说,如果需要事务支持,并且有较高的并发读取频率,InnoDB是不错的选择。
MEMORY
    使用MySQL Memory存储引擎的出发点是速度。为得到最快的响应时间,采用的逻辑存储
介质是系统内存。虽然在内存中存储表数据确实会提供很高的性能,但当mysqld守护进程崩
溃时,所有的Memory数据都会丢失。获得速度的同时也带来了一些缺陷。它要求存储在Memory
数据表里的数据使用的是长度不变的格式,这意味着不能使用BLOB和TEXT这样的长度可变的数
据类型,VARCHAR是一种长度可变的类型,但因为它在MySQL内部当做长度固定不变的CHAR类型,
所以可以使用。
    一般在以下几种情况下使用Memory存储引擎:

    1.目标数据较小,而且被非常频繁地访问。在内存中存放数据,所以会造成内存的使用,
    可以通过参数max_heap_table_size控制Memory表的大小,设置此参数,就可以限制Memory
    表的最大大小。

    2.如果数据是临时的,而且要求必须立即可用,那么就可以存放在内存表中。

    3.存储在Memory表中的数据如果突然丢失,不会对应用服务产生实质的负面影响。
8、java GC
    堆分为三块、新域(YG)、旧域(OG)、永久域。新域用于存储新生成的对象,旧域用于
存储生命周期较长的对象,永久域用于存储类和方法对象(默认为4M)。
    新域分为三块空间,Eden、From Space、To Space。Eden用于存储刚出生的对象,当Eden满
了的时候,应用停止,GC开始运行,将Eden中的对象进行垃圾清理,将还在活动的对象复制到
From Space,当From Space被充满时,GC同样开始工作,将From Space中还在活动的对象复制到
To Space,原先From Space被清空,形成空闲区域。当To Space充满时再检测活动对象转移至
From Space,To Space形成空闲面,经过一定次数的循环之后,仍存活的对象将被转移至旧域。
这样转换的操作目的是为了减少短命对象存储的时间,避免资源浪费。
    当旧域被充满时,会触发full gc(有待商榷),full gc会对YG和OG中存有的垃圾进行回收,
并同时阻塞线程,十分消耗资源和时间。
    对新域的gc操作叫做MinorGC,对旧域的gc叫做MajorGC,两个GC互不干涉。full gc同时对og
和yg进行回收,MajorGC只对OG回收,是有区别的。(System.gc是full gc)
    新域的gc算法为copying算法,旧域为tracing算法(称为标记、清除、压缩收集器)。
    所有的GC都会触发所有线程阻塞,但是MinorGC的时间较短可以忽略。

    堆空间的大小影响了GC的时间,GC时间过久会影响程序运行,通常设置堆内存为物理内存的80%左右。

----------------------------------------------------------------------------------------------------------------------------------------------2018/12/18

9、MYSQL INNODB幻读问题
    innodb行锁分为:
    record lock:锁单行记录(唯一索引为此锁)
    gap lock:一段范围的间隙内
    next-key lock:类似record lock+gap lock
    innodb(REPEATABLE-READ级别)采用快照读(consistent read view)加Next-Key Lock
解决幻读,事务开始后每次对一行数据进行crud操作时会标记一个snapshot事务号,每次读取
都只会读取标有相应事务号的数据,成为快照读。
    Next-Key Lock,在对某行数据进行检索时,会锁住一个范围内的数据。
    特例:事务A先查询,事务B后新增数据并提交,事务A再查询,此时结果与第一次相同。
事务A update之前事务B新增的数据,这里会产生更新了没有看见的数据的情况,再次查询
会多出B新增后A更新的数据,是因为更新后也为此行数据增加了事务号,且同一事务中事务号
一致。(此例中如有Next-Key Lock则不会发生)
    mysql默认不加Next-Key Lock,如需加锁需在sql后加for update
    MVCC:mysql表前有三个隐藏字段,一个为版本号,一个为事务号,一个为回滚指针。
insert操作会对版本号+1,select会检索所有小于等于此次read view所获得的版本号的数据,
update会先复制一份原有数据至undo log,并将混滚指针指向它,再修改数据。

    RR与RC一致性读的区别:简单而言,RC隔离级别时,事务中的每一条select语句会读取到

他自己执行时已经提交了的记录,也就是每一条select都有自己的一致性读ReadView; 而RR隔

离级别时,事务中的一致性读的ReadView是以第一条select语句的运行时,作为本事务的一致

性读snapshot的建立时间点的,所以只能读取该时间点之前已经提交的数据。

    rc下的半一致性读:rc下执行update,如读到加锁行,会返回记录最新提交的版本,然后
交由Mysql上层判断是否满足where语句,如果满足,再次发起读操作(等待锁释放并加锁)。
而RR则会直接阻塞,这样做的好处是减少了update语句行锁冲突,如果不满足where则会直接
跳过减少并发冲突的概率。

10、java内存模型

java内存分为:

一、所有线程共享(某种意义上可称为主内存):

    ----方法区:保存类信息及一些常量等

    ----堆:存放所有对象

二、线程私有(某种意义上可称为工作空间):

    ----虚拟机栈:可以存在多个,每个线程独立,个数取决线程数

    ----本地方法栈

    ----程序计数器:用于记录字节码运行的行号

    所有变量都必须存储在主内存,各个线程对变量进行修改时需要从主内存拷贝至工作内存,修改,

再更新至主内存。(每个线程的工作内存独立,线程间通信需要靠主内存完成)

11、synchorized和lock

    synchorized是非公平锁,lock可以设置为公平锁。

    synchorized是java关键字,lock是接口。

    ReentrantLock为Lock实现类,主要解决synchorized在线程等待锁过程中无法打断的问题。(lockInterruptibly()方法)

    ReenTrantLock与synchorized都为可重入锁。

    lock的实现类ReenTrantReadWriteLock内置读锁和写锁,多线程读时不会阻塞,有写锁参与时都会发生阻塞。

12、类加载器

    1、BootstrpClassLoader:c++编写,加载%JAVA_HOME%/jre/lib以及%JAVA_HOME%/jre/classes下的class(rt.jar等)

    2、ExtClassLoader  :java编写,加载%JAVA_HOME%/jre/lib/ext下的class

 3、AppClassLoader :java编写,加载classpath下的class(加载应用的主要加载器)

    关系:BootstrpClassLoader加载ExtClassLoader  ,ExtClassLoader  加载AppClassLoader ,父加载器为各自的上级

   双亲委派模型:加载一个类时会先从父加载器检索是否存在这个类,存在就用父加载器检索到的类,不存在再加载(为了防止恶意类被加载,比如恶意编写的java.lang.String,由于双亲委派模型所以只会加载之前BootstrpClassLoader加载的String。ps:所有的java.*都被规定只能由BootstrpClassLoader加载)

   j2ee应用:web容器有自己的类加载器实现,且不同的是他先检索当前类,找不到再交给父加载器,这么做是为了让web应用的类优先级高于web容器提供的类。

13、注解

注解编译过后是接口,用来注解注解的注解叫做元注解,如@Target、@Retention、@Documented、@Inherited

@Target用于限定注解使用位置(如方法,类,字段)

@Retention用于限定注解生命周期,如@Retention(RetentionPolicy.RUNTIME)会编译进class文件,jvm能识别。

@Documented用于生成javadoc,用@Documented标注的内容会生成于javadoc

@Inherited 可以让注解被继承,但这并不是真的继承,只是通过使用@Inherited,可以让子类Class对象使用getAnnotations()获取父类被@Inherited修饰的注解

通过传递全路径后通过Class.forName()方法获取到class对象,然后利用Class对象中的方法获取所有成员字段Field,最后利用field.getDeclaredAnnotations()遍历每个Field上的注解再通过注解的类型判断来实现操作。这便是利用注解结合反射的处理器模型。(类似hibernate注解)
 

14、mysql索引算法

mysql索引主要为hash索引和bTree索引。

    bTree索引其实类似二分查找,复杂度为O(Logn),可以被用在=,>,>=,<,<=和between这些比较操作符上,而且还可以用于like操作符,只要它的查询条件是一个不以通配符开头的常量。

    Hash索引只能用于=,in(),等(相当于=)操作符。由于是哈希定位,所以检索效率远高于BTree索引。

    But: bTree的使用一般多于hash索引,原因如下1、hash索引不支持范围查询 。2、联合索引时不支持最优前缀(即全部索引字段使用时才生效,因为哈希索引是根据所有索引列计算的哈希码,而btree只要索引第一列字段存在即可,例如联合索引ABC,那么使用A,AB,ABC都会生效,但AC只会生效A的索引,BC无索引,创建联合索引ABC的本质是创建了A,AB,ABC三个索引)。3、由于是哈希结构,索引存储的是键的哈希码和行指针,所以除了检索完索引后还需进行一次行读取,那么如果在哈希冲突较大情况下效率可能反而没有BTREE来的高。

15、单例模式

//以下内容参考自https://blog.csdn.net/javazejian/article/details/71333103 

public class Singleton {
    //volatile禁止指令重排序
    private static volatile Singleton singleton = null;//懒加载,解决不必要资源浪费

    private Singleton(){}

    public static Singleton getInstance(){
        if(singleton == null){
            synchronized (Singleton.class){//同步代码块而不同步方法,解决synchronized效率低下
                if(singleton == null){双重null检查,提高效率,后续可避免进入同步块
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }    
}

//除此外静态内部类也能满足1、懒加载2、多线程安全3、效率问题
public class SingletonInner {
    private static class Inner {
        //这部分会在使用到内部类时加载,即实现了懒加载
        private static SingletonInner singleton = new SingletonInner();
    }

    private SingletonInner(){}

    public static SingletonInner getSingleton(){
        return Inner.singleton;
    }
}

//以上两种方法无法防止两个问题:反序列化可生成多个对象;反射得到构造器可生成对个对象

//枚举单例模式
public enum  SingletonEnum {
    INSTANCE;

    private String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
}
/*
  1、枚举序列化是由jvm保证的,每一个枚举类型和定义的枚举变量在JVM中都是唯一的
  2、创建枚举实例只有编译器能够做到,反射枚举类时会抛出异常
  3、枚举类都是static的,由classloader保证了线程安全
  4、缺点:不是懒加载
*/

16、class对象

类加载过程分为:加载、链接、初始化

加载:查找字节码文件并生成class对象

链接:验证字节码安全性完整性、为静态域与静态成员变量分配存储空间

初始化:执行静态初始化器和静态初始化成员变量,初始化后才会将class对象(之前在加载过程创建的)加载进内存。

三种方式获取class对象:Object中的getClass()方法,class.forName()方法,.class字面量方法(如Class clazz = String.class)

getClass()和forName()都会触发类加载最终阶段初始化,而.class则不进入初始化阶段。

ps:用static 和 final修饰的常量叫做编译期静态常量,会存储到常量池,以后的引用会从常量池中取,所以用.class字面量方式获取的class对象去调用其编译期静态常量时也不会触发初始化。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值