北京微网站建设建设银行互联网网站

当前位置: 首页 > news >正文

北京微网站建设,建设银行互联网网站,网站推广计划书模板,医疗产品网站建设目录一.java基础1.八大基础类型2.java三大特性3.重载和重写的区别4.pubilc、protected、(dafault)不写、private修饰符的作用范围5.和equals的区别6.hashcode()值相同#xff0c;equals就一定为true7.short s 1#xff1b;s s 1#xff1b;(程序1)和 short s 1#xff… 目录一.java基础1.八大基础类型2.java三大特性3.重载和重写的区别4.pubilc、protected、(dafault)不写、private修饰符的作用范围5.和equals的区别6.hashcode()值相同equals就一定为true7.short s 1s s 1(程序1)和 short s 1 s 1(程序2)是否都能正常运行8.说出下面程序的运行结果及原因9.和的区别10.String、StringBuffer、StringBuilder的区别11.String rap new String(ctrl);创建了几个对象12.什么是反射13.浅拷贝和深拷贝的区别14构造器能被重写吗15.并发和并行16.实例变量和类变量。17.说出下面程序的运行结果及原因18.抽象类和接口的区别19.Error和Exception有什么区别20.NoClassDefFoundError和ClassNotFoundException区别21.如果try{} 里有一个 return 语句那么finalfly{} 里的代码会不会被执行什么时候被执行在 return 前还是后?22.看一面代码执行结果是啥22.final关键字有哪些用法23.jdk1.8的新特性24.http中重定向和转发的区别25.get和post请求的区别 delete、put26.cookie和session的区别27.java中的数据结构28.什么是跨域?跨域的三要素29.tomcat三个默认端口及其作用30.throw 和 throws 的区别31.说一下你熟悉的设计模式二.java集合1.List、Set、Map的区别2.List、Set、Map常用集合有哪些3.什么是哈希表4.什么是哈希冲突5.解决哈希冲突6.HashMap的hash()算法为什么不是hkey.hashcode(),而是key.hashcode()^ (h16)7.为什么HashMap的初始容量和扩容都是2的次幂8.HashMap如果指定了不是2的次幂的容量会发生什么9.HashMap为什么线程不安全10.解决Hashmap的线程安全问题11.ConcurrentHashMap的原理12.为什么用synchronized代替ReentrantLock13.HashMap为什么使用链表14.HashMap为什么使用红黑树15.HashMap为什么不一上来就使用红黑树16.说说你对红黑树的理解17.为什么链表长度大于8并且表的长度大于64的时候链表会转换成红黑树18.为什么转成红黑树是8呢而重新转为链表阈值是6呢19.为什么负载因子是0.7520.什么时候会扩容21.为什么不是满了扩容22.扩容过程23.HashMap和Hashtable的区别三.多线程1.线程是什么多线程是什么2.守护线程和用户线程3.线程的各个状态4.线程相关的基本方法有 waitnotifynotifyAllsleepjoinyield 等5.wait()和sleep()的区别6.为什么 wait()、notify()、notifyAll()方法定义在 Object 类里面而不是 Thread 类7.实现多线程的方式8.Runnable和Callable的区别9.线程池的好处10.线程池的七大参数11.线程池的执行过程12.四大方法13.四大拒绝策略14.什么是死锁15.造成死锁的四个必要条件16.线程安全主要是三方面17.volatile和synchronized的区别18.synchronized和lock的区别四.jvm1.jvm是什么2.jvm的作用3.java文件的加载过程4.jdk、jre、jvm的区别5.类加载器的作用6.类加载器的类型7.双亲委派机制的加载过程8.双亲委派机制的优缺点9.为什么要打破双亲委派机制10.打破双亲委派机制的方式11.jvm的每个部分储存的都是什么12.内存溢出(oom)和栈溢出13.垃圾回收的作用区域14.怎么判断对象是否可回收15.四种引用类型 强引用 软引用 弱引用 虚引用16.垃圾回收算法17.轻GCMinor GC和 重GCFull GC18.什么时候会发生重GC五.锁1.悲观锁和乐观锁2.悲观锁和乐观锁的场景3.自旋锁和自适应自旋锁4.无锁、偏向锁、轻量级锁、重量级锁5.公平锁和非公平锁6.可重入锁7.独享锁和共享锁8.互斥锁和读写锁9.分段锁10.锁优化技术后续会持续更新,广告回来更精彩如果想看原理可以看看我的另几篇文章没有过多的讲解原理你们只要背会了就能快乐两年半。一.java基础 1.八大基础类型 数字型 字节类型(byte)、短整型short、整型int、长整型Long、单精度浮点数float、双精度浮点数double 字符型 字符类型char、 布尔型 布尔类型boolean、 2.java三大特性 封装 使用private关键字让对象私有防止无关的程序去使用。 继承 继承某个类使子类可以使用父类的属性和方法。 多态 同一个行为不同的子类具有不同的表现形式。 3.重载和重写的区别 重载 发生在同一类中函数名必须一样参数类型、参数个数、参数顺序、返回值、修饰符可以不一样。 重写 发生在父子类中函数名、参数、返回值必须一样访问修饰符必须大于等于父类异常要小于等于父类父类方法是private不能重写。 4.pubilc、protected、(dafault)不写、private修饰符的作用范围 pubilc 同类、同包、子类、不同包都可以使用。 protected 同类、同包、子类可以使用不同包不能。 (dafault)不写 同类、同包可以使用子类、不同包不能。 private 只有同类可以。 5.和equals的区别 基础类型比较的值引用类型比较的是地址值。 equals 默认比较的是值。重写之后比较的是两个对象是否相同比如String类重写equals源码首先比较是否都是String对象然后再向下比较。 6.hashcode()值相同equals就一定为true 不一定因为 重地和通话的hashcode值就相同但是equals()就为false。 但是equals()为true那么hashcode一定相同。 7.short s 1s s 1(程序1)和 short s 1 s 1(程序2)是否都能正常运行 程序1会编译报错因为 s 1的1是int类型因为类型不兼容。强制转换失败。 程序2可以正常运行因为java在复合赋值解释是 E1 E2,等价于 E1 (T)(E1 E2),T是E1的类型因此s 1等价于 s (short)(s 1)所以进行了强制类型的转换所以可以正常编译。 8.说出下面程序的运行结果及原因 public static void main(String[] args) {Integer a 128, b 128, c 127, d 127;System.out.println(a b);System.out.println(c d); } 结果falsetrue因为Integer a相当于自动装箱(基础类型转为包装类)因为Integer引入了IntegerCache来缓存一定的值IntegerCache默认是 -128~127所以128超过了范围a和b不是相同对象c和d是相同对象。 可以通过jvm启动时修改缓存的上限。 9.和的区别 如果一边为假就不比较另一边。具有短路行 : 两边都为假结果才为假多用于位运算。 10.String、StringBuffer、StringBuilder的区别 String 适用于少量字符串。创建之后不可更改对String的修改会生成新的String对象。 StringBuilder 适用于大量字符串线程不安全性能更快。单线程使用 StringBuffer 适用于大量字符串线程安全。多线程使用用synchronized关键字修饰。 11.String rap new String(“ctrl”);创建了几个对象 一个或两个如果常量池存在那就在堆创建一个实例对象否则常量池也需要创建一个。 12.什么是反射 在运行过程中对于任何一个类都能获取它的属性和方法任何一个对象都能调用其方法动态获取信息和动态调用就是反射。 13.浅拷贝和深拷贝的区别 浅拷贝 基础数据类型复制值引用类型复制引用地址修改一个对象的值另一个对象也随之改变。 深拷贝 基础数据类型复制值引用类型在新的内存空间复制值新老对象不共享内存修改一个值不影响另一个。 深拷贝相对浅拷贝速度慢开销大。 14构造器能被重写吗 不能可以被重载。 15.并发和并行 并发 一个处理器同时处理多个任务。(一个人同时吃两个苹果) 并行 多个处理器同时处理多个任务。(两个人同时吃两个苹果) 16.实例变量和类变量。 类变量是被static所修饰的没有被static修饰的叫实例变量也叫成员变量。同理也存在类对象和实例对象类方法和实例方法。 //类变量 public static String kunkun1 鸡你太美;//实例变量(成员变量) public String kunkun2 鸡你不美;17.说出下面程序的运行结果及原因 public class InitialTest {public static void main(String[] args) {A ab new B();ab new B();} } class A {static { // 父类静态代码块System.out.print(A);}public A() { // 父类构造器System.out.print(a);} } class B extends A {static { // 子类静态代码块System.out.print(B);}public B() { // 子类构造器System.out.print(b);} }结果ABabab原因 ①执行顺序是 父类静态代码块(父类静态变量) - 子类静态代码块(子类静态变量) - 父类非静态代码块 - 父类构造方法 - 子类非静态代码块 - 子类构造方法 ②静态代码块(静态变量)只执行一次。 18.抽象类和接口的区别 抽象类只能单继承接口可以实现多个。 抽象类有构造方法接口没有构造方法。 抽象类可以有实例变量接口中没有实例变量有常量。 抽象类可以包含非抽象方法接口在java7之前所有方法都是抽象的java之后可以包含非抽象方法。 抽象类中方法可以是任意修饰符接口中java8之前都是publicjava9支持private。 扩展普通类是亲爹会被怎么学都告诉你抽象类(多个类具有相同的东西拿出来放抽象类)是师傅教你一部分秘籍然后告诉你怎么学。接口(规范了某些行为)是干爹只给你秘籍怎么学全靠你。 19.Error和Exception有什么区别 Error 程序无法处理比较严重的问题程序会立即崩溃jvm停止运行。 Exception 程序本身可以处理(向上抛出或者捕获)。编译时异常和运行时异常 20.NoClassDefFoundError和ClassNotFoundException区别 NoClassDefFoundError在打包时漏掉了某些类或者打包时存在然后你把target里的类删除然后jvm运行时找不到报错。 ClassNotFoundException在编译的时候某些类找不到然后报错。 21.如果try{} 里有一个 return 语句那么finalfly{} 里的代码会不会被执行什么时候被执行在 return 前还是后? 会执行在return之前执行如果finally有return那么try的return就会失效。 22.看一面代码执行结果是啥 public class TryDemo {public static void main(String[] args) {System.out.println(test1());}public static int test1() {int i 0;try {i 2;return i;} finally {i 3;}} } 结果 2因为在return前jvm会把2暂存起来所以当i改变了回到try时还是会返回暂存的值。 22.final关键字有哪些用法 修饰类 不能被继承。 修饰方法 不能被重写。 修饰变量 声明时给定初始值只能读取不能修改。如果是对象引用不能改但是对象的属性可以修改。 23.jdk1.8的新特性 ①lambda 表达式 ②方法引用 ③加入了base64的编码器和解码器 ④函数式接口 ⑤接口允许定义非抽象方法使用default关键字即可 ⑥时间日期类改进 24.http中重定向和转发的区别 重定向发送两次请求转发发送一次请求 重定向地址栏会变化转发地址栏不会变化 重定向是浏览器跳转转发是服务器跳转 重定向可以跳转任意网址转发只能跳转当前项目 重定向会有数据丢失转发不会数据丢失 25.get和post请求的区别 delete、put get是不安全的数据放在url中post相对来说安全 get传送的数据量小post传送的数据量大 get效率比post高是form的默认提交方法 26.cookie和session的区别 存储位置不同cookie放在客户端电脑session放在服务器端内存的一个对象 存储容量不同cookie 4KB,一个站点最多保存20个cookiesession是没有上限的但是性能考虑不要放太多而且要设置session删除机制 存储方式不同cookie只能存储ASCLL字符串session可以存储任何类型的数据 隐私策略不同cookie放在本地别人可以解析进行cookie欺骗session放在服务器不存在敏感信息泄露 有效期不同可以设置cookie的过期时间session依赖于jsessionID的cookie默认时间为-1只需要关闭窗口就会失效 27.java中的数据结构 数组、链表、哈希表、栈、堆、队列、树、图 28.什么是跨域?跨域的三要素 跨域指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的是浏览器施加的安全限制 协议、域名、端口 注意localhost和127.0.0.1虽然都指向本机但也属于跨域 29.tomcat三个默认端口及其作用 8005这个端口负责监听关闭tomcat的请求。 8009接受其他服务器的请求 8080用于监听浏览器发送的请求 30.throw 和 throws 的区别 throw抛出一个异常。 throws声明一个异常。 31.说一下你熟悉的设计模式 单例模式 保证被创建一次节省系统开销。 工厂模式 解耦代码。 观察者模式 定义了对象之间的一对多的依赖这样一来当一个对象改变时它的所有的依赖者都会收到通知并自动更新。 代理模式 代理对象具备被代理对象的功能并代替被代理对象完成相应操作并能够在操作执行的前后对操作进行增强处理。 模板模式 较少代码冗余。例如redis模板。 二.java集合 1.List、Set、Map的区别 List集合有序、可重复的单例集合。 Set集合无序、不可重复的单例集合。 Map集合有序、k不可重复v可重复的双例集合。 2.List、Set、Map常用集合有哪些 List vector 底层是数组方法加了synchronized来保证线程安全所以效率较慢使用ArrayList替代。 ArrayList 线程不安全底层是数组因为数组都是连续的地址所以查询比较快。增删比较慢增会生成一个新数组把新增的元素和原有元素放到新数组中删除会导致元素移动所以增删速度较慢。 LinkedList 线程不安全底层是链表因为地址不是连续的都是一个节点和一个节点相连每次查询都得重头开始查询所以查询慢增删只是断裂某个节点对整体影响不大所以增删速度较快。 Set HashSet 底层是哈希表(数组链表或数组红黑树)在链表长度大于8时转为红黑树在红黑树节点小于6时转为链表。其实就是实现了HashMap值存入keyvalue是一个final修饰的对象。 TreeSet 底层是红黑树结构就是TreeMap实现可以实现有序的集合。String和Integer可以根据值进行排序。如果是对象需要实现Comparator接口重写compareTo()方法制定比较规则。 LinkedHashSet 实现了HashSet多一条链表来记录位置所以是有序的。 Mapkey,value双例结构 TreeMap 底层是红黑树key可以按顺序排列。 HashMap 底层是哈希表可以很快的储存和检索无序大量迭代情况不佳。 LinkedHashMap 底层是哈希表链表有序大量迭代情况佳。 3.什么是哈希表 根据关键码值(Key value)而直接进行访问的数据结构在一个表中通过H(key)计算出key在表中的位置H(key)就是哈希函数表就是哈希表。 4.什么是哈希冲突 不用的key通过哈希函数计算出相同的储存地址这就是哈希冲突。 5.解决哈希冲突 (1)开放地址法 如果发生哈希冲突就会以当前地址为基准再去寻找计算另一个位置直到不发生哈希冲突也叫再散列方法。 寻找的方法有① 线性探测 123m ② 二次探测 1的平方-1的平方2的平方-2的平方k的平方-k的平方km/2 ③ 随机探测 生成一个随机数然后从随机地址随机数。 (2)链地址法 冲突的哈希值连到到同一个链表上。 (3)再哈希法 多个哈希函数发生冲突就在用另一个算计直到没有冲突。 (4)建立公共溢出区 哈希表分成基本表和溢出表与基本表发生冲突的都填入溢出表。 6.HashMap的hash()算法为什么不是hkey.hashcode(),而是key.hashcode()^ (h16) 得到哈希值然后右移16位然后进行异或运算这样使哈希值的低16位也具有了一部分高16位的特性增加更多的变化性减少了哈希冲突。 7.为什么HashMap的初始容量和扩容都是2的次幂 因为计算元素存储的下标是(n-1)哈希值数组初始容量-1得到的二进制都是1这样可以减少哈希冲突可以更好的均匀插入。 8.HashMap如果指定了不是2的次幂的容量会发生什么 会获得一个大于指定的初始值的最接近2的次幂的值作为初始容量。 9.HashMap为什么线程不安全 jdk1.7中因为使用头插法再扩容的时候可能会造成闭环和数据丢失。 jdk1.8中使用尾插法不会出现闭环和数据丢失但是在多线程下会发生数据覆盖。(put操作中在putVal函数里) 值的覆盖还要长度的覆盖。 10.解决Hashmap的线程安全问题 (1)使用Hashtable解决在方法加同步关键字所以效率低下已经被弃用。 (2)使用Collections.synchronizedMap(new HashMap()),不常用。 (3)ConcurrentHashMap(常用) 11.ConcurrentHashMap的原理 jdk1.7 采用分段锁是由Segment(继承ReentrantLock可重入锁默认是16并发度是16)和HashEntry内部类组成每一个Segment(锁)对应1个HashEntry(keyvalue)数组数组之间互不影响实现了并发访问。 jdk1.8 抛弃分段锁采用CAS(乐观锁)synchronized实现更加细粒度的锁Node数组链表红黑树结构。只要锁住链表的头节点(树的根节点)就不会影响其他数组的读写提高了并发度。 12.为什么用synchronized代替ReentrantLock ①节省内存开销。ReentrantLock基于AQS来获得同步支持但不是每个节点都需要同步支持只有链表头节点或树的根节点需要同步所以使用ReentrantLock会带来很大的内存开销。 ②获得jvm支持可重入锁只是api级别而synchronized是jvm直接支持的能够在jvm运行时做出相应的优化。 ③在jdk1.6之后对synchronized做了大量的优化而且有多种锁状态会从 无锁 - 偏向锁 - 轻量级锁 - 重量级锁一步步转换。 13.HashMap为什么使用链表 减少和解决哈希冲突把冲突的值放在同一链表下。 14.HashMap为什么使用红黑树 当数据过多链表遍历较慢所以引入红黑树。 15.HashMap为什么不一上来就使用红黑树 维护成本较大红黑树在插入新的数据后可能会进行变色、左旋、右旋来保持平衡所以当数据少时就不需要红黑树。 16.说说你对红黑树的理解 ①根节点是黑色。 ②节点是黑色或红色。 ③叶子节点是黑色。 ④红色节点的子节点都是黑色。 ⑤从任意节点到其子节点的所有路径都包含相同数目的黑色节点。 红黑树从根到叶子节点的最长路径不会超过最短路径的2倍。保证了红黑树的高效。 17.为什么链表长度大于8并且表的长度大于64的时候链表会转换成红黑树 因为链表长度越长哈希冲突概率就越小当链表等于8时哈希冲突就非常低了是千万分之一我们的map也不会存那么多数据如果真要存那么多数据那就转为红黑树提高查询和插入的效率。 18.为什么转成红黑树是8呢而重新转为链表阈值是6呢 因为如果都是8的话那么会频繁转换会浪费资源。 19.为什么负载因子是0.75 加载因子越大填满的元素越多空间利用率越高但发生冲突的机会变大了 加载因子越小填满的元素越少冲突发生的机会减小但空间浪费了更多了而且还会提高扩容rehash操作的次数。 “冲突的机会”与“空间利用率”之间寻找一种平衡与折中。 又因为根据泊松分布当负载因子是0.75时平均值时0.5带入可得当链表为8时哈希冲突发生概率就很低了。 20.什么时候会扩容 元素个数 数组长度 * 负载因子 例如 16 * 0.75 12,当元素超过12个时就会扩容。 链表长度大于8并且表长小于64也会扩容 21.为什么不是满了扩容 因为元素越多空间利用率是高了但是发生哈希冲突的几率也增加了。 22.扩容过程 jdk1.7 会生成一个新table然后会把旧table复制到新table因为是头插法在线程不安全的时候可能会出现闭环和数据丢失。 jdk1.8 记录旧table和新table新table是旧table长度的两倍然后循环旧table把元素插入进新table。 23.HashMap和Hashtable的区别 ①HashMap运行key和value为nullHashtable不允许为null。 ②HashMap线程不安全Hashtable线程安全。 三.多线程 1.线程是什么多线程是什么 线程 是最小的调度单位包含在进程中。 多线程 多个线程并发执行的技术。 2.守护线程和用户线程 守护线程 jvm给的线程。比如GC守护线程。 用户线程 用户自己定义的线程。比如main()线程。 拓展 Thread.setDaemon(false)设置为用户线程 Thread.setDaemon(true)设置为守护线程 3.线程的各个状态 新建(New): 新建一个线程。 就绪(Runnable): 抢夺cpu的使用权。 运行(Running): 开始执行任务。 阻塞(Blocked) 让线程等待等待结束进入就绪队列。 死亡(Dead) 线程正常结束或异常结束。 4.线程相关的基本方法有 waitnotifynotifyAllsleepjoinyield 等 wait() 线程等待会释放锁用于同步代码块或同步方法中进入等待状态 sleep() 线程睡眠不会释放锁进入超时等待状态 yield() 线程让步会使线程让出cpu使用权进入就绪状态 join() 指定的线程加入到当前线程可以将两个交替执行的线程合并为顺序执行的线程。 notify() 随机唤醒一个在等待中的线程进入就绪状态。 notifyAll() 唤醒全部在等待中的线程进入就绪状态。 5.wait()和sleep()的区别 ① wait() 来自Objectsleep()来自Thread。 ② wait()会释放锁sleep()不会释放锁。 ③ wait()只能用在同步方法或代码块中sleep()可以用在任何地方。 ④ wait()不需要捕获异常sleep()需要捕获异常。 6.为什么 wait()、notify()、notifyAll()方法定义在 Object 类里面而不是 Thread 类 ① 锁可以是任何对象如果在Thread类中那只能是Thread类的对象才能调用上面的方法了。 ② java中进入临界区(同步代码块或同步方法)线程只需要拿到锁就行而并不关心锁被那个线程持有。 ③ 上面方法是java两个线程之间的通信机制如果不能通过类似synchronized这样的Java关键字来实现这种机制那么Object类中就是定义它们最好的地方以此来使任何Java对象都可以拥有实现线程通信机制的能力。 7.实现多线程的方式 ①继承Thread类。 ②实现Runnable接口 ③实现Callable接口 ④线程池 8.Runnable和Callable的区别 ①Runnable没有返回值Callable有返回值。 ②Runnable只能抛出异常不能捕获Callable 能抛出异常也能捕获。 9.线程池的好处 ① 线程是稀缺资源使用线程池可以减少线程的创建和销毁每个线程都可重复使用。 ② 可以根据系统的需求调整线程池里面线程的个数防止了因为消耗内存过多导致服务器崩溃。 10.线程池的七大参数 corePoolSize 核心线程数创建不能被回收可以设置被回收。 maximumPoolSize 最大线程数。 keepAliveTime 空闲线程存活时间。 unit 单位。 workQueue 等待队列。 handler 拒绝策略。 11.线程池的执行过程 ①接到任务判断核心线程池是否满了没满执行任务满了放入等待队列。 ②等待队列没满存入队列等待执行满了去查看最大线程数。 ③最大线程数没满执行任务满了执行拒绝策略。 12.四大方法 ①ExecutorService executor Executors.newCachedThreadPool() 创建一个缓存线程池灵活回收线程任务过多会oom。 ②ExecutorService executor Executors.newFixedThreadPool() 创建一个指定线程数量的线程池。提高了线程池的效率和线程的创建的开销等待队列可能堆积大量请求导致oom。 ③ExecutorService executor Executors.newSingleThreadPool() 创建一个单线程保证线程的有序出现异常再次创建速度没那么快。 ④ExecutorService executor Executors.newScheduleThreadPool() 创建一个定长的线程池支持定时及周期性任务执行。 13.四大拒绝策略 ①new ThreadPoolExecutor.AbortPolicy() 添加线程池被拒绝会抛出异常(默认策略)。 ②new ThreadPoolExecutor.CallerRunsPolicy() 添加线程池被拒绝不会放弃任务也不会抛出异常会让调用者线程去执行这个任务(就是不会使用线程池里的线程去执行任务会让调用线程池的线程去执行)。 ③new ThreadPoolExecutor.DiscardPolicy() 添加线程池被拒绝丢掉任务不抛异常。 ④new ThreadPoolExecutor.DiscardOldestPolicy() 添加线程池被拒绝会把线程池队列中等待最久的任务放弃把拒绝任务放进去。 14.什么是死锁 各进程互相等待对方手里的资源导致各进程都阻塞无法向前推进的现象。 15.造成死锁的四个必要条件 互斥 当资源被一个线程占用时别的线程不能使用。 不可抢占 进程阻塞时对占用的资源不释放。 不剥夺 进程获得资源未使用完不能被强行剥夺。 循环等待 若干进程之间形成头尾相连的循环等待资源关系。 16.线程安全主要是三方面 原子性 操作不可分割要么全部执行并且不能被打断否则全部不执行。 可见性 可见性是指当多个线程访问同一个变量时一个线程修改了这个变量的值其他线程能够立即看得到修改的值。 有序性 程序执行的顺序按照代码的先后顺序执行。 保证原子性 使用锁 synchronized和 lock。 使用CAS (compareAndSet比较并交换CAS是cpu的并发原语)。 保证可见性 使用锁 synchronized和 lock。 使用volatile关键字 。 保证有序性 使用 volatile 关键字 使用 synchronized 关键字。 17.volatile和synchronized的区别 ① volatile仅能使用在变量级别的synchronized可以使用在变量、方法、类级别的 ② volatile不具备原子性具备可见性synchronized有原子性和可见性。 ③ volatile不会造成线程阻塞synchronized会造成线程阻塞。 ④ volatile关键字是线程同步的轻量级实现所以volatile性能肯定比synchronized要好。 18.synchronized和lock的区别 ① synchronized是关键字lock是java类默认是不公平锁源码。 ② synchronized适合少量同步代码lock适合大量同步代码。 ③ synchronized会自动释放锁lock必须放在finally中手工unlock释放锁不然容易死锁。 四.jvm 1.jvm是什么 java虚拟机是实现java跨平台的核心组件。 2.jvm的作用 java中所有的类必须被装载到jvm中才能使用装载由类加载器完成.class这个类型可以在虚拟机运行但不是直接和操作系统交互需要jvm解释给操作系统解释的时候需要java类库这样就能和操作系统交互。 3.java文件的加载过程 .java - .class - 类加载器 - jvm 4.jdk、jre、jvm的区别 jdk 包含java运行环境和开发环境、jvm、java类库。 jre 包含java运行环境和jvm、java类库。 jvm java虚拟机是跨平台的核心组件。 5.类加载器的作用 将.class文件装载到jvm中实质就是把文件从硬盘写到内存。 6.类加载器的类型 引导类加载器(Bootstrap ClassLoder) c编写jvm自带的加载器负责加载java核心类库该加载器无法直接获取。 拓展类加载器(Extension ClassLoder) 加载jre/lib/etc目录下的jar包。 系统类加载器(Application ClassLoder) 加载当前项目目录下的类或jar包最常用的加载器。 自定义加载器(Custom ClassLoder) 开发人员自定义的。需要继承ClassLoader 7.双亲委派机制的加载过程 ①接到类加载的请求。 ②向上委托给父类加载器直到引导类加载器。 ③引导类加载器检查能否加载当前这个类如果能使用当前加载器请求结束如果不能抛出异常通知子加载器进行加载。 ④重复③。 8.双亲委派机制的优缺点 优点保证类加载的安全性不管那个类被加载都会被委托给引导类加载器只有类加载器不能加载才会让子加载器加载这样保证最后得到的对象都是同样的一个。 缺点子加载器可以使用父加载器加载的类而父加载器不能使用子加载器加载的类。 9.为什么要打破双亲委派机制 子加载器可以使用父加载器加载的类而父加载器不能使用子加载器加载的类。 例如使用JDBC连接数据库需要用到 com.mysql.jdbc.Driver和DriverManager类。然而DriverManager被引导类加载器所加载而com.mysql.jdbc.Driver被当前调用者的加载器加载使用引导类加载器加载不到所以要打破双亲委派机制。 10.打破双亲委派机制的方式 ① 自定义类加载器重写loadclass方法。 ② 使用线程上下文类(ServiceLoader使父加载器可以加载子加载器的类)。 11.jvm的每个部分储存的都是什么 方法区(线程共享) 常量池、静态(static)变量以及方法信息(方法名、返回值、参数、修饰符等)等。 堆(线程共享) 是虚拟机内存中最大的一块储存的是实例对象。 本地方法栈(线程不共享) 调用的本地方法被native修饰的方法java不能直接操作操作系统所以需要native修饰的方法帮助。 虚拟机栈(线程不共享) 8大基本类型、对象引用、实例方法。 程序计数器(线程不共享) 每个线程启动是都会创建一个程序计数器保存的是正在执行的jvm指令程序计数器总是指向下一条将被执行指令的地址。 12.内存溢出(oom)和栈溢出 内存溢出的原因 (1)内存使用过多或者无法垃圾回收的内存过多使运行需要的内存大于提供的内存。 (2)长期持有某些资源并且不释放从而使资源不能及时释放也称为内存泄漏。 解决 (1)进行jvm调优。-Xmxjvm最大内存。-Xms:启动初始内存。-Xmn新生代大小。 -Xss:每个虚拟机栈的大小。 (2)使用专业工具测试。 手动制造 一直new对象就ok。 栈溢出原有 线程请求的栈容量大于分配的栈容量。 解决 (1)修改代码 (2)调优 -Xss 手动制造 一直调用实例方法。 13.垃圾回收的作用区域 作用在方法区和堆主要实在堆中的伊甸园区。年轻代分为(伊甸园区和幸存区) 14.怎么判断对象是否可回收 可达性分析算法 简单来说就是一个根对象通过引用链向下走能走到的对象都是不可回收的。可作为根对象有 虚拟机栈的引用的对象本地栈的引用的对象方法区引用的静态和常量对象。 引用计数算法 每个对象都添加一个计数器每多一个引用指向对象计数器就加一如果计数器为零那么就是可回收的。 15.四种引用类型 强引用 软引用 弱引用 虚引用 强引用 基于可达性分析算法只有当对象不可达才能被回收否则就算jvm满了也不会被回收会抛出oom。 软引用 一些有用但是非必须的对象当jvm即将满了会将软引用关联对象回收回收之后如果内存还是不够会抛出oom。 弱引用 不论内存是否够只要开始垃圾回收软引用的关联对象就会被回收。 虚引用 最弱的引用和没有一样随时可能被回收。 16.垃圾回收算法 标记-清除算法(适用老年代) 先把可回收的对象进行标记然后再进行清除。 优点算法简单。 缺点产生大量的内存碎片效率低。 复制算法(适用年轻代) 把内存分成两个相同的块一个是from一个是to每次只使用一个块当一个块满了就把存活的对象放到另一个块中然后清空当前块。主要用在年轻区中的幸存区。 优点效率较高没有内存碎片。 缺点内存利用率低。 标记-整理算法(适用老年代) 标记-清除算法的升级版也叫标记-压缩算法先进行标记然后让存活对象向一端移动然后清除掉边界以外的内存。 有点解决了内存利用率低和避免了内存碎片。 缺点增加了一个移动成本。 17.轻GCMinor GC和 重GCFull GC 轻GC 普通GC当新对象在伊甸园区申请内存失败时进行轻GC会回收可回收对象没有被回收的对象进入幸存区新对象分配内存极大部分都是在伊甸园区所以这个区GC比较频繁。一个对象经历15次GC会进入老年区可以设置。 重GC 全局GC对整个堆进行回收所以要比轻GC慢因此要减少重GC我们所说的jvm调优大部分都是针对重GC。 18.什么时候会发生重GC ①当老年区满了会重GC年轻区对象进入或创建大对象会满。 ②永久代满了会重GC。 ③方法区满了会重GC。 ④system.gc()会重GC 。 ⑤轻GC后进入老年代的大小大于老年代的可用内存会第一次轻GC进入老年代要2MB第二次的时候会判断是否大于2MB不满足就会重GC。 五.锁 1.悲观锁和乐观锁 悲观锁 在修改数据时一定有别的线程来使用所以在获取数据的时候会加锁。java中的synchronized和Lock都是悲观锁。 乐观锁 在修改数据时一定没有别的线程来使用所以不会添加锁。但是在更新数据的时候会查看有没有线程修改数据。比如版本号和CAS原理(无锁算法)。 2.悲观锁和乐观锁的场景 悲观锁 更适合写操作多的场景因为先加锁可以保证数据的正确。 乐观锁 更适合读操作多的场景因为不加锁会让读操作的性能提升。 3.自旋锁和自适应自旋锁 前言因为线程竞争会导致线程阻塞或者挂起但是如果同步资源的锁定时间很短那么阻塞和挂起的花费的资源就得不偿失。 自旋锁 当竞争的同步资源锁定时间短就让线程自旋如果自旋完成后资源释放了锁那线程就不用阻塞直接获取资源减少了切换线程的开销。实现原理是CAS。 缺点占用了处理器的时间如果锁被占用的时间短还好如果长那就白白浪费了处理器的时间。所以要限定自旋次数默认是10次可以使用-XX:PreBlockSpin来更改没有成功获得锁就应当挂起线程。 自适应自旋锁 自旋次数不固定是由上一个在同一个锁上的自旋时间和锁拥有者的状态决定。如果在同一个锁对象上自旋刚刚获得锁并且持有锁的线程在运行那么虚拟机会认为这次自旋也可能成功那么自旋的时间就会比较长如果某个锁自旋没成功获得过那么可能就会直接省掉自旋进入阻塞避免浪费处理器时间。 4.无锁、偏向锁、轻量级锁、重量级锁 这四个锁是专门针对synchronized的在 JDK1.6 中对 synchronized 锁的实现引入了大量的优化并且 synchronized 有多种锁状态。级别从低到高依次是无锁、偏向锁、轻量级锁和重量级锁。锁状态只能升级不能降级。 无锁 就是乐观锁。 偏向锁 当只有一个线程访问加锁的资源不存在多线程竞争的情况下那么线程不需要重复获取锁这时候就会给线程加一个偏向锁。(对比Mark Word解决加锁问题避免CAS操作) 轻量级锁 是指当锁是偏向锁的时候被另外的线程所访问偏向锁就会升级为轻量级锁其他线程会通过自旋的形式尝试获取锁不会阻塞从而提高性能。(CAS自旋) 重量级锁 若当前只有一个等待线程则该线程通过自旋进行等待。但是当自旋超过一定的次数或者一个线程在持有锁一个在自旋又有第三个来访时轻量级锁升级为重量级锁。(将除了拥有锁的线程以外的线程都阻塞) 5.公平锁和非公平锁 公平锁 多个线程按照申请锁的顺序来获取锁。 Lock lock new ReentrantLock(true); 默认是非公平锁设置为true是公平锁。 优点等待线程不会饿死。 缺点CPU唤醒线程得开销比非公平锁要大。 非公平锁 多个线程获取锁的顺序并不是按照申请锁的顺序。 sybchronized和lock都是非公平锁。 优点减少唤醒线程得开销。 缺点可能会出现线程饿死或者很久获得不了锁。 6.可重入锁 可重入锁 也叫递归锁同一个线程在外层方法获取了锁在进入内层方法会自动获取锁。(提前锁对象是同一个对象或者类)。ReentrantLock和synchronized都是可重入锁。 7.独享锁和共享锁 独享锁 独占锁是指锁一次只能被一个线程所持有。如果一个线程对数据加上排他锁后那么其他线程不能再对该数据加任何类型的锁。获得独占锁的线程即能读数据又能修改数据。synchronized和Lock的显示类就是独占锁。 共享锁 共享锁是指锁可被多个线程所持有。如果一个线程对数据加上共享锁后那么其他线程只能对数据再加共享锁不能加独占锁。获得共享锁的线程只能读数据不能修改数据。 8.互斥锁和读写锁 互斥锁 是独享锁的实现某一资源同时只允许一个访问者对其访问。具有唯一和排它性。 读写锁 是共享锁的实现读写锁管理一组锁一个是只读的锁一个是写锁。读锁可以在没有写锁的时候被多个线程同时持有而写锁是独占的。写锁的优先级要高于读锁。并发度要比互斥锁高因为可以拥有多个读锁。 9.分段锁 是锁的设计不是具体的某一种锁分段锁的设计目的是细化锁的粒度当操作不需要更新整个数组的时候就仅仅针对数组中的一项进行加锁操作。 ConcurrentHashMap的锁机制jdk1.7用的就是分段锁。 10.锁优化技术 锁粗化 将多个同步块的数量减少并将单个同步块的作用范围扩大本质上就是将多次上锁、解锁的请求合并为一次同步请求。 锁消失 锁消除是指虚拟机编译器在运行时检测到了共享数据没有竞争的锁从而将这些锁进行消除。 参考 https://blog.csdn.net/guoguo527/article/details/118004077 https://www.cnblogs.com/jyroy/p/11365935.html