Java开发工程师2年需要掌握的基础知识

最近好不容易闲下来了,组上的小朋友问我工作两年了需要掌握什么,把我问到了,特意想了一下 两年的经验正常情况下需要掌握什么而不是只是会CRUD,简单归纳一下 做个记录吧.
1.Java内存模型(堆,栈)
    a) Java内存模型
        Java虚拟机将其管辖的内存大致分三个逻辑部分:方法区(Method Area)、Java栈和Java堆。
        (1)方法区是静态分配的,编译器将变量绑定在某个存储位置上,而且这些绑定不会在运行时改变。
    常数池,源代码中的命名常量、String常量和static变量保存在方法区。
        (2)Java Stack是一个逻辑概念,特点是后进先出。一个栈的空间可能是连续的,也可能是不连续的。
        最典型的Stack应用是方法的调用,Java虚拟机每调用一次方法就创建一个方法帧(frame),退出该方法则对应的  方法帧被弹出(pop)。栈中存储的数据也是运行时确定的。
        (3)Java堆分配(heap allocation)意味着以随意的顺序,在运行时进行存储空间分配和收回的内存管理模型。
        堆中存储的数据常常是大小、数量和生命期在编译时无法确定的。Java对象的内存总是在heap中分配。
        我们每天都在写代码,每天都在使用JVM的内存。
    b) java内存分配
         (1)基础数据类型直接在栈空间分配;
         (2)方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收;
         (3)引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量;
         (4)方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完后从栈空间回收;
         (5)局部变量 new 出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收;
         (6)方法调用时传入的实际参数,先在栈空间分配,在方法调用完成后从栈空间释放;
         (7)字符串常量在 DATA 区域分配 ,this 在堆空间分配;
         (8)数组既在栈空间分配数组名称, 又在堆空间分配数组实际的大小!
2.垃圾回收
    GC在回收对象前必须先发现哪些是无用的对象,
    ?如何判断哪些对象是无用的
        !搜索算法
            (1)根搜索算法
                通过一些"GC Roots"对象作为起点,从这些节点往下搜索,搜索通过的路径成为引用链,如果一个对象没有被GC Roots的引用链连接,说明这个对象是不可用的
            (2)引用技术器算法(已废弃)
    ?回收算法
        (1)标记--清楚算法
            标记—清除算法包括两个阶段:“标记”和“清除”。在标记阶段,确定所有要回收的对象,并做标记。清除阶段紧随标记阶段,将标记阶段确定不可用的对象清除。标记—清除算法是基础的收集算法,标记和清除阶段的效率不高,而且清除后回产生大量的不连续空间,这样当程序需要分配大内存对象时,可能无法找到足够的连续空间。
        (2)复制算法
            复制算法是把内存分成大小相等的两块,每次使用其中一块,当垃圾回收的时候,把存活的对象复制到另一块上,然后把这块内存整个清理掉。复制算法实现简单,运行效率高,但是由于每次只能使用其中的一半,造成内存的利用率不高。现在的JVM用复制方法收集新生代,由于新生代中大部分对象(98%)都是朝生夕死的,所以两块内存的比例不是1:1(大概是8:1)。
        (3)标记-整理算法
            标记—整理算法和标记—清除算法一样,但是标记—整理算法不是把存活对象复制到另一块内存,而是把存活对象往内存的一端移动,然后直接回收边界以外的内存。标记—整理算法提高了内存的利用率,并且它适合在收集对象存活时间较长的老年代。
        (4)分代收集
            分代收集是根据对象的存活时间把内存分为新生代和老年代,根据各个代对象的存活特点,每个代采用不同的垃圾回收算法。新生代采用复制算法,老年代采用标记—整理算法。垃圾算法的实现涉及大量的程序细节,而且不同的虚拟机平台实现的方法也各不相同。
3.JVM配置
    XMX,XMS
4.多线程:
    sleep(),wait()区别
        wait()的作用是让当前线程由运行状态进入等待阻塞状态,而sleep()的作用也是让线程由运行状态进入阻塞状态
        不同的是wait()会释放对象的同步锁,而sleep()则不会释放锁
        wait通常被用于线程间交互,sleep通常被用于暂停执行。
5.线程池
6.arrayList是线程安全的吗
    ArrayList,Hashset,HashMap都不是是线程安全的,
    Vector和hashTable是线程安全的,打开源码可以看到各自的核心方法上加了synchronized关键字
    collections工具类提供了相关的API,可以让三个不安全的集合变为安全的
    collections.synchronizedCollection(c)
    collections.synchronizedList(list)
    collections.synchronizedMap(m)
    collections.synchronizedSet(s)
    上面几个函数都有对应的返回值类型,传入什么类型就返回什么类型,打开源码可以看到就是将集合的核心方法加了synchronized关键字
7.设计模式:单例模式
    创建型模型(共五种):工厂方法模式,抽象工厂模式,单例模式,建造者模式
    结构型模式(共七种):适配器模式,代理模式,
    行为型模式(共十一种):策略模式,观察者模式
    
    (1)单例模式:
        分为懒汉式和饿汉式和登记式,适用于一个类只有一个实例的情况
        懒汉式:在第一次调用方法的时候会做一个判断,如果实例不存在,则创建一个,如果实例存在,则直接返回。延迟加载,比如配置文件,被用到的时候才会加载
            //懒汉式单例模式  
            public class MySingleton {  
              
                //设立静态变量  
                private static MySingleton mySingleton = null;  
              
                private MySingleton(){  
                    //私有化构造函数  
                    System.out.println("-->懒汉式单例模式开始调用构造函数");  
                }  
                  
                //开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回  
                public static MySingleton getInstance(){  
                    System.out.println("-->懒汉式单例模式开始调用公有方法返回实例");  
                    if(mySingleton == null){  
                        System.out.println("-->懒汉式构造函数的实例当前并没有被创建");  
                        mySingleton = new MySingleton();  
                    }else{  
                        System.out.println("-->懒汉式构造函数的实例已经被创建");  
                    }  
                    System.out.println("-->方法调用结束,返回单例");  
                    return mySingleton;  
                }  
            }  
        饿汉式:一开始就加载了。
        //饿汉式单例模式  
        public class MySingleton2 {  
          
            //设立静态变量,直接创建实例  
            private static MySingleton2 mySingleton = new MySingleton2();  
          
            private MySingleton2(){  
                //私有化构造函数  
                System.out.println("-->饿汉式单例模式开始调用构造函数");  
            }  
              
            //开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回  
            public static MySingleton2 getInstance(){  
                System.out.println("-->饿汉式单例模式开始调用公有方法返回实例");  
                return mySingleton;  
            }  
        }  
        如果说懒汉式是时间换空间,那么饿汉式就是空间换时间
        饿汉式虽然节省了时间,但是浪费了空间;
        懒汉式影响程序的加载速度,同时,在并发的情况下,懒汉式是不安全的
        如何改进:可以加synchronized关键字
    (2)    工厂模式
        工厂模式可以分为工厂方法模式和抽象工厂模式
            工厂方法模式又可以分为普通工厂模式,多个工厂方法模式,静态工厂方法模式
            普通工厂模式:多个类实现同一个接口,工厂类的作用是在实例化类的时候会做一个判断
                比如有一个接口为fruit
                有apple,banana两个类都实现了fruit的接口
                在实例化类的时候会判断
                if(apple.equals(type)){
                    return new Apple();
                }else if(banana.equals(type)){
                    return new Banana();
                }else{
                    system.out.println("请输入正确的类型");
                    return null;
                }    
            多个工厂方法模式:是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象
                一个工厂类里面有多个创建不同对象的方法,使用时,先实例化工厂类,在使用工厂类调用里面的方法
            静态工厂方法模式:就是将上面多个工厂方法模式里的方法置为静态的,不需要创建示例,直接调用就可以
        抽象工厂模式:
            工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码
    (3)适配器设计模式
    (4)装饰模式
8.volidate
    一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
  1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
  2)禁止进行指令重排序。
    volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;
    synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    
    (1).volatile仅能使用在变量级别;
        synchronized则可以使用在变量、方法、和类级别的
    (2).volatile仅能实现变量的修改可见性,并不能保证原子性;
        synchronized则可以保证变量的修改可见性和原子性
    (3).volatile不会造成线程的阻塞;
        synchronized可能会造成线程的阻塞。
    (4).volatile标记的变量不会被编译器优化;
        synchronized标记的变量可以被编译器优化
9.threadLocal
    ThreadLocal用于创建线程的本地变量,我们知道一个对象的所有线程会共享它的全局变量,所以这些变量不是线程安全的,我们可以使用同步技术。但是当我们不想使用同步的时候,我们可以选择ThreadLocal变量。
    每个线程都会拥有他们自己的Thread变量,它们可以使用get()\set()方法去获取他们的默认值或者在线程内部改变他们的值。ThreadLocal实例通常是希望它们同线程状态关联起来是private static属性。
10.mysql:开源,可以自己定制
    索引:什么样的字段要加索引
11.事务
    读未提交
    读已提交
    重读
    串行化
12.mysql索引:hash,BTree
    (1)hash索引查找数据基本上能一次定位数据,当然有大量碰撞的话性能也会下降。而btree索引就得在节点上挨着查找了,很明显在数据精确查找方面hash索引的效率是要高于btree的;
    (2) 那么不精确查找呢,也很明显,因为hash算法是基于等值计算的,所以对于“like”等范围查找hash索引无效,不支持;
    (3)对于btree支持的联合索引的最优前缀,hash也是无法支持的,联合索引中的字段要么全用要么全不用。提起最优前缀居然都泛起迷糊了,看来有时候放空得太厉害;
    (4)hash不支持索引排序,索引值和计算出来的hash值大小并不一定一致。
    
    ?查看索引执行的情况
        执行语句show status like '%Handler_read%';
        查询结果分析:
            如果索引正在工作,则Handler_read_key的值会很高,这个值代表一个行被索引值读的次数,很低值表名增加索引得到的性能改善不高,因此索引并不经常使用
            如果Handler_read_rnd_next值很高意味着查询运行效率很低,应该建立索引补救,这个值含义是在数据文件中读取下一行的请求数。如果正在进行大量表扫描,Handler_read_rnd_next的数值将会很高。说明索引不正确或者没有利用索引。
    
    ?如何查看那些sql语句执行比较慢:mysql慢日志
    ?mysql语句优化:
        (1)select * from admin left join log on admin.admin_id = log.admin_id where log.admin_id>10
            优化后:select * from (select * from admin where admin_id>10) T1 lef join log on T1.admin_id = log.admin_id。
            使用JOIN 时候,应该用小的结果驱动大的结果(left join 左边表结果尽量小如果有条件应该放到左边先处理,right join 同理反向)
        (2)limit 的基数比较大时使用between
            例如:select * from admin order by admin_id limit 100000,10
            优化为:select * from admin where admin_id between 100000 and 100010 order by admin_id。
        (3)尽量避免在列上做运算,这样导致索引失效
            例如:select * from admin where year(admin_time)>2014
            优化为: select * from admin where admin_time> '2014-01-01′
13.读写分离:程序里面怎么实现读写分离
    在进入Service之前,使用AOP来做出判断,是使用写库还是读库,判断依据可以根据方法名判断,比如说以query、find、get等开头的就走读库,其他的走写库。
    如果事务管理中配置了事务策略,则采用配置的事务策略中的标记了ReadOnly的方法是用Slave,其它使用Master。
    如果没有配置事务管理的策略,则采用方法名匹配的原则,以query、find、get开头方法用Slave,其它用Master。
14.Redis:数据类型:字符串(string),字典(hash),列表(List),集合(set),有序集合(Sorted Set)
    常用命令:set,get,del,incr(递增),decr(递减),
    单线程?多线程?
    setNX命令:set if Not exists
        setNX可以用来实现分布式锁
        SETNX key value,将key的值设为value,当且仅当key不存在
    redis持久化方式
    redis事务
15.负载策略:随机,轮询(配置权重),活跃调用数,一致性hash
16.tomcat:session共享
    可以在tomcat里面做一些设置,使用 filter 方法存储,使用 tomcat sessionmanager 方法存储。会暂用IO资源
    可以存在Redis里面
17.单点登陆
18.zookeeper上面的节点类型
    持久节点:创建之后就一直存在,直到有删操作来主动清楚这个节点
    持久顺序节点:在持久节点的基础上,每个父节点为他的第一级子节点维护一份时序,记录每个子节点创建的先后顺序
    临时节点:临时节点的生命周期和客户端会话绑定,如果客户端会话失效,这个节点也会自动被清除
    临时顺序节点:可以用来实现分布式锁
19.solr:深分页
    Solr必须为返回的搜索结果准备一个列表,并返回它的一部分。如果该部分来源于该列表的前面并不难。但如果我们想返回第10000页(每页20条记录)的数据,Solr需要准备一个包含大小为200000(10000 * 20)的列表。这样,它不仅需要时间,还需要内存。像我们现在生产上的历史数据达到了6个亿的数据,如果直接跳转到最后一页,必定内存溢出。
    Solr4.7的发布改变了这一状况,引入了游标的概念。游标是一个动态结构,不需要存储在服务器上。游标包含了查询的结果的偏移量,因此,Solr的不再需要每次从头开始遍历结果直到我们想要的记录,游标的功能可以大幅提升深翻页的性能。
    执行第一个查询的时候,传递一个参数:cursorMark,告诉solr返回游标,在返回的结果中可以得到nextCursorMark信息,使用这个值作为我们翻下一页的参数
20.lucene:倒排索引
21.MQ:保证顺序消费
22.分布式的锁
    
23.什么是死锁(Deadlock)?如何分析和避免死锁
    死锁是指两个以上的线程永远阻塞的情况,这种情况产生至少需要两个以上的线程和两个以上的资源。
    分析死锁,我们需要查看Ja
    储。我们需要找出那些状态为BLOCKED的线程和他们等待的资源。每个资源都有一个唯一的id,用这个id我们可以找出哪些线程已经拥有了它的对象锁。
    避免嵌套锁,只在需要的地方使用锁和避免无限期等待是避免死锁的通常办法,
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿邱先森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值