主题网站建设福州交通建设集团官方网站

张小明 2025/12/30 20:48:36
主题网站建设,福州交通建设集团官方网站,网站推广计划至少应包括,chatgpt app我相信大多 Java 开发的程序员或多或少经历过 BAT 一些大厂的面试#xff0c;也清楚一线互联网大厂 Java 面试是有一定难度的#xff0c;小编经历过多次面试#xff0c;有满意的也有备受打击的。因此呢小编想把自己这么多次面试经历以及近期的面试真题来个汇总分析#xff…我相信大多 Java 开发的程序员或多或少经历过 BAT 一些大厂的面试也清楚一线互联网大厂 Java 面试是有一定难度的小编经历过多次面试有满意的也有备受打击的。因此呢小编想把自己这么多次面试经历以及近期的面试真题来个汇总分析阐述下如何去准备去回答面试官的提问可以和面试官有个愉快的交谈。小编分享的这份 BAT 必考 Java 真题合集包含了性能调优、并发编程、框架源码、分布式框架、微服务架构、项目实战、互联网工具等七个大专题技术点真题模块分享都是小编在各个大厂面试总结出来的面试真题已经有很多粉丝靠这份真题合集拿下金三银四的面试今天小编在这里总结分享给到大家目录1、 JDK 和 JRE 有什么区别2、 和 equals 的区别是什么3、final 在 java 中有什么作用4、java 中的 Math.round(-1.5) 等于多少5、String 属于基础的数据类型吗6、String stri与 String strnew String(“i”)一样吗7、如何将字符串反转8、String 类的常用方法都有那些9、new String(a) new String(b) 会创建几个对象10、如何将字符串反转11、String 类的常用方法都有那些12、普通类和抽象类有哪些区别13、接口和抽象类有什么区别14、java 中 IO 流分为几种15、 BIO、 NIO、 AIO 有什么区别16、Files的常用方法都有哪些17、什么是 反射18、什么是 java 序列化什么情况下需要序列化19、为什么要使用克隆如何实现对象克隆深拷贝和浅拷贝区别是什么20、throw 和 throws 的区别21、final、finally、finalize 有什么区别22、try-catch-finally 中如果 catch 中 return 了finally 还会执行吗23、常见的异常类有哪些24、hashcode是什么有什么作用25、java 中操作字符串都有哪些类它们之间有什么区别26、java 中都有哪些引用类型27、在 Java 中为什么不允许从静态方法中访问非静态变量28、说说Java Bean的命名规范29、Java Bean 属性命名规范问题分析30、什么是 Java 的内存模型?31、在 Java 中什么时候用重载什么时候用重写32、举例说明什么情况下会更倾向于使用抽象类而不是接口33、实例化对象有哪几种方式34、byte类型1271等于多少35、Java 容器都有哪些36、Collection 和 Collections 有什么区别37、list与Set区别38、HashMap 和 Hashtable 有什么区别39、说一下 HashMap 的实现原理40、set有哪些实现类41、说一下 HashSet 的实现原理42、ArrayList 和 LinkedList 的区别是什么43、如何实现数组和 List 之间的转换44、在 Queue 中 poll()和 remove()有什么区别45、哪些集合类是线程安全的46、迭代器 Iterator 是什么47、Iterator 怎么使用有什么特点48、Iterator 和 ListIterator 有什么区别49、怎么确保一个集合不能被修改50、队列和栈是什么有什么区别51、Java8开始ConcurrentHashMap,为什么舍弃分段锁52、ConcurrentHashMap(JDK1.8)为什么要使用synchronized而不是如ReentranLock这样的可重入锁53、concurrentHashMap和HashTable有什么区别54、HasmMap和HashSet的区别55、请谈谈 ReadWriteLock 和 StampedLock56、线程的run()和start()有什么区别57、为什么我们调用 start() 方法时会执行 run() 方法为什么我们不能直接调用 run() 方法58、Synchronized 用过吗其原理是什么59、JVM 对 Java 的原生锁做了哪些优化60、为什么 wait(), notify()和 notifyAll()必须在同步方法或者同步块中被调用61、Java 如何实现多线程之间的通讯和协作62、Thread 类中的 yield 方法有什么作用63、为什么说 Synchronized 是非公平锁64、请谈谈 volatile 有什么特点为什么它能保证变量对所有线程的可见性65、为什么说 Synchronized 是一个悲观锁乐观锁的实现原理又是什么什么是 CAS它有什么特性66、乐观锁一定就是好的吗67、请尽可能详尽地对比下 Synchronized 和 ReentrantLock 的异同。68、ReentrantLock 是如何实现可重入性的69、什么是锁消除和锁粗化70、跟 Synchronized 相比可重入锁 ReentrantLock 其实现原理有什么不同71、那么请谈谈 AQS 框架是怎么回事儿72、AQS 对资源的共享方式73、如何让 Java 的线程彼此同步74、你了解过哪些同步器请分别介绍下。75、Java 中的线程池是如何实现的76、创建线程池的几个核心构造参数77、线程池中的线程是怎么创建的是一开始就随着线程池的启动创建好的吗78、volatile 关键字的作用79、既然 volatile 能够保证线程间的变量可见性是不是就意味着基于 volatile 变量的运算就是并发安全的80、 ThreadLocal 是什么有哪些使用场景81、请谈谈 ThreadLocal 是怎么解决并发安全的82、很多人都说要慎用 ThreadLocal谈谈你的理解使用 ThreadLocal 需要注意些什么83、为什么代码会重排序84、什么是自旋85、多线程中 synchronized 锁升级的原理是什么86、synchronized 和 ReentrantLock 区别是什么87、Java Concurrency API 中的 Lock 接口(Lock interface)是什么对比同步它有什么优势88、jsp 和 servlet 有什么区别89、jsp 有哪些内置对象作用分别是什么90、forward 和 redirect 的区别91、说一下 jsp 的 4 种作用域92、session 和 cookie 有什么区别93、如果客户端禁止 cookie 能实现 session 还能用吗94、什么是上下文切换95、cookie、session、token96、说一下 session 的工作原理97、http 响应码 301 和 302 代表的是什么有什么区别98、简述 tcp 和 udp的区别99、tcp 为什么要三次握手两次不行吗为什么100、OSI 的七层模型都有哪些101、get 和 post 请求有哪些区别102、什么是 XSS 攻击如何避免103、什么是 CSRF 攻击如何避免104、如何实现跨域说一下 JSONP 实现原理105、websocket应用的是哪个协议106、说一下 tcp 粘包是怎么产生的107、请列举出在 JDK 中几个常用的设计模式108、什么是设计模式你是否在你的代码里面使用过任何设计模式109、Java 中什么叫单例设计模式请用 Java 写出线程安全的单例模式110、在 Java 中什么叫观察者设计模式observer design pattern111、使用工厂模式最主要的好处是什么在哪里使用112、请解释自动装配模式的区别113、举一个用 Java 实现的装饰模式(decorator design pattern)它是作用于对象层次还是类层次114、什么是 Spring 框架Spring 框架有哪些主要模块115、使用 Spring 框架能带来哪些好处116、Spring IOC、AOP举例说明117、什么是控制反转(IOC)什么是依赖注入118、BeanFactory 和 ApplicationContext 有什么区别119、什么是 JavaConfig120、什么是 ORM 框架121、Spring 有几种配置方式122、请解释 Spring Bean 的生命周期123、Spring Bean 的作用域之间有什么区别Spring容器中的bean可以分为5个范围124、如何在 Spring Boot 中禁用 Actuator 端点安全性125、什么是 Spring inner beans126、Spring 框架中的单例 Beans 是线程安全的么127、请解释 Spring Bean 的自动装配128、如何开启基于注解的自动装配129、什么是 Spring Batch130、spring mvc 和 struts 的区别是什么131、请举例解释Required 注解132、Spring常用注解133、项目中是如何实现权限验证的权限验证需要几张表134、谈谈controller接口调用的路径问题135、如何防止表单重复提交136、Spring中都应用了哪些设计模式137、请举例说明如何在 Spring 中注入一个 Java Collection138、 mybatis 中 #{}和 ${}的区别是什么139、mybatis 是否支持延迟加载延迟加载的原理是什么140、说一下 mybatis 的一级缓存和二级缓存141、mybatis 有哪些执行器Executor142、mybatis 和 hibernate 的区别有哪些143、myBatis查询多个id、myBatis常用属性144、mybatis一级缓存、二级缓存145、mybatis如何防止sql注入146、hibernate 中如何在控制台查看打印的 sql 语句147、hibernate 有几种查询方式148、hibernate 实体类可以被定义为 final 吗149、在 hibernate 中使用 Integer 和 int 做映射有什么区别150、什么是 Spring BootSpring Boot 有哪些优点151、Spring Boot 中的监视器是什么152、什么是 YAML153、如何使用 Spring Boot 实现分页和排序154、如何使用 Spring Boot 实现异常处理155、单点登录156、Spring Boot比Spring多哪些注解157、打包和部署158、Spring Boot如何访问不同的数据库159、查询网站在线人数160、easyExcel如何实现161、什么是 Swagger你用 Spring Boot 实现了它吗162、数据库的三范式是什么163、一张自增表里面总共有 7 条数据删除了最后 2 条数据重启 mysql 数据库又插入了一条数据此时 id 是几164、如何获取当前数据库版本165、说一下 ACID 是什么166、char 和 varchar 的区别是什么167、float 和 double 的区别是什么168、Oracle分页sql169、数据库如何保证主键唯一性170、如何设计数据库171、性别是否适合做索引172、如何查询重复的数据173、数据库一般会采取什么样的优化方法174、索引怎么定义分哪几种175、mysql 的内连接、左连接、右连接有什么区别176、 RabbitMQ的使用场景有哪些177、RabbitMQ有哪些重要的角色有哪些重要的组件178、RabbitMQ中 vhost 的作用是什么179、说一下 jvm 的主要组成部分及其作用180、说一下 jvm 运行时数据区181、什么是类加载器类加载器有哪些182、说一下类加载的执行过程183、JVM的类加载机制是什么184、什么是双亲委派模型185、怎么判断对象是否可以被回收186、说一下 jvm 有哪些垃圾回收算法187、说一下 jvm 有哪些垃圾回收器188、JVM栈堆概念何时销毁对象189、新生代垃圾回收器和老生代垃圾回收器都有哪些有什么区别190、详细介绍一下 CMS 垃圾回收器191、简述分代垃圾回收器是怎么工作的192、 Redis是什么193、Redis都有哪些使用场景194、Redis有哪些功能195、Redis支持的数据类型有哪些196、Redis取值存值问题197、Redis为什么是单线程的198、Redis真的是单线程的吗199、Redis持久化有几种方式200、Redis和 memecache 有什么区别201、Redis支持的 java 客户端都有哪些202、jedis 和 redisson 有哪些区别203、什么是缓存穿透怎么解决204、怎么保证缓存和数据库数据的一致性205、Redis什么是缓存穿透怎么解决206、Redis怎么实现分布式锁207、Redis分布式锁有什么缺陷208、Redis如何做内存优化篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题需要完整版的小伙伴可以在文末获取1、JDK 和 JRE 有什么区别JDKJava Development KitJava开发工具包JREJava Runtime EnvironmentJava运行环境JDK中包含JREJDK中有一个名为jre的目录里面包含两个文件夹bin和libbin就是JVMlib就是JVM工作所需要的类库。2、 和 equals 的区别是什么对于基本类型比较的是值对于引用类型比较的是地址equals不能用于基本类型的比较如果没有重写equalsequals就相当于如果重写了equals方法equals比较的是对象的内容3、final 在 java 中有什么作用final修饰的成员变量必须在声明的同时赋值一旦创建不可修改final修饰的方法不能被子类重写final类中的方法默认是final的private类型的方法默认是final的4、java 中的 Math.round(-1.5) 等于多少Math提供了三个与取整有关的方法ceil、floor、round1ceil向上取整Math.ceil(11.3) 12;Math.ceil(-11.3) 11;2floor向下取整Math.floor(11.3) 11;Math.floor(-11.3) -12;3round四舍五入加0.5然后向下取整。Math.round(11.3) 11;Math.round(11.8) 12;Math.round(-11.3) -11;Math.round(-11.8) -12;5、String 属于基础的数据类型吗不属于。八种基本数据类型byte、short、char、int、long、double、float、boolean。6、String stri与 String strnew String(“i”)一样吗String stri会将起分配到常量池中常量池中没有重复的元素如果常量池中存中i就将i的地址赋给变量如果没有就创建一个再赋给变量。String strnew String(“i”)会将对象分配到堆中即使内存一样还是会重新创建一个新的对象。7、如何将字符串反转将对象封装到stringBuilder中调用reverse方法反转。8、String 类的常用方法都有那些1常见String类的获取功能length获取字符串长度charAt(int index)获取指定索引位置的字符indexOf(int ch)返回指定字符在此字符串中第一次出现处的索引substring(int start)从指定位置开始截取字符串,默认到末尾substring(int start,int end)从指定位置开始到指定位置结束截取字符串2常见String类的判断功能equals(Object obj) 比较字符串的内容是否相同,区分大小写contains(String str): 判断字符串中是否包含传递进来的字符串startsWith(String str): 判断字符串是否以传递进来的字符串开头endsWith(String str): 判断字符串是否以传递进来的字符串结尾isEmpty(): 判断字符串的内容是否为空串3常见String类的转换功能byte[] getBytes(): 把字符串转换为字节数组char[] toCharArray(): 把字符串转换为字符数组String valueOf(char[] chs): 把字符数组转成字符串。valueOf可以将任意类型转为字符串toLowerCase(): 把字符串转成小写toUpperCase(): 把字符串转成大写concat(String str): 把字符串拼接4常见String类的其他常用功能replace(char old,char new) 将指定字符进行互换replace(String old,String new) 将指定字符串进行互换trim() 去除两端空格int compareTo(String str) 会对照ASCII 码表 从第一个字母进行减法运算 返回的就是这个减法的结果如果前面几个字母一样会根据两个字符串的长度进行减法运算返回的就是这个减法的结果如果连个字符串一摸一样 返回的就是0。9、new String(a) new String(b) 会创建几个对象对象1new StringBuilder()对象2new String(a)对象3常量池中的a对象4new String(b)对象5常量池中的b深入剖析StringBuilder中的toString()对象6new String(ab)强调一下toString()的调用在字符串常量池中没有生成ab附加题String s1 new String(1) new String(1);//s1变量记录的地址为new Strings1.intern();//在字符串常量池中生成11。如何理解jdk6创建了一个新的对象11也就有新的地址jdk7此时常量池中并没有创建11而是创建了一个指向堆空间中new String(11)的地址String s2 11;System.out.println(s1 s2);//jdk6:false;jdk7:true10、如何将字符串反转添加到StringBuilder中然后调用reverse()。11、String 类的常用方法都有那些equals、length、contains、replace、split、hashcode、indexof、substring、trim、toUpperCase、toLowerCase、isEmpty等等。12、普通类和抽象类有哪些区别抽象类不能被实例化抽象类可以有抽象方法只需申明无须实现有抽象方法的类一定是抽象类抽象类的子类必须实现抽象类中的所有抽象方法否则子类仍然是抽象类抽象方法不能声明为静态、不能被static、final修饰。13、接口和抽象类有什么区别1接口接口使用interface修饰接口不能实例化类可以实现多个接口①java8之前接口中的方法都是抽象方法省略了public abstract。②java8之后接口中可以定义静态方法静态方法必须有方法体普通方法没有方法体需要被实现2抽象类抽象类使用abstract修饰抽象类不能被实例化抽象类只能单继承抽象类中可以包含抽象方法和非抽象方法非抽象方法需要有方法体如果一个类继承了抽象类①如果实现了所有的抽象方法子类可以不是抽象类②如果没有实现所有的抽象方法子类仍然是抽象类。14、java 中 IO 流分为几种1按流划分可以分为输入流和输出流2按单位划分可以分为字节流和字符流字节流inputStream、outputStream字符流reader、writer15、BIO、NIO、AIO 有什么区别1同步阻塞BIO一个连接一个线程。JDK1.4之前建立网络连接的时候采用BIO模式先在启动服务端socket然后启动客户端socket对服务端通信客户端发送请求后先判断服务端是否有线程响应如果没有则会一直等待或者遭到拒绝请求如果有的话会等待请求结束后才继续执行。2同步非阻塞NIONIO主要是想解决BIO的大并发问题BIO是每一个请求分配一个线程当请求过多时每个线程占用一定的内存空间服务器瘫痪了。JDK1.4开始支持NIO适用于连接数目多且连接比较短的架构比如聊天服务器并发局限于应用中。一个请求一个线程。3异步非阻塞AIO一个有效请求一个线程。JDK1.7开始支持AIO适用于连接数目多且连接比较长的结构比如相册服务器充分调用OS参与并发操作。16、Files的常用方法都有哪些existcreateFilecreateDirectorywritereadcopysizedeletemove17、什么是反射所谓反射是java在运行时进行自我观察的能力通过class、constructor、field、method四个方法获取一个类的各个组成部分。在Java运行时环境中对任意一个类可以知道类有哪些属性和方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于反射机制。18、什么是 java 序列化什么情况下需要序列化序列化就是一种用来处理对象流的机制。将对象的内容流化将流化后的对象传输于网络之间。序列化是通过实现serializable接口该接口没有需要实现的方法implement Serializable只是为了标注该对象是可被序列化的使用一个输出流FileOutputStream来构造一个ObjectOutputStream对象接着使用ObjectOutputStream对象的writeObejctObject object方法就可以将参数的obj对象到磁盘需要恢复的时候使用输入流。序列化是将对象转换为容易传输的格式的过程。例如可以序列化一个对象然后通过HTTP通过Internet在客户端和服务器之间传输该对象。在另一端反序列化将从流中心构造成对象。一般程序在运行时产生对象这些对象随着程序的停止而消失但我们想将某些对象保存下来这时我们就可以通过序列化将对象保存在磁盘需要使用的时候通过反序列化获取到。对象序列化的最主要目的就是传递和保存对象保存对象的完整性和可传递性。譬如通过网络传输或者把一个对象保存成本地一个文件的时候需要使用序列化。19、为什么要使用克隆如何实现对象克隆深拷贝和浅拷贝区别是什么1什么要使用克隆想对一个对象进行复制又想保留原有的对象进行接下来的操作这个时候就需要克隆了。2如何实现对象克隆实现Cloneable接口重写clone方法实现Serializable接口通过对象的序列化和反序列化实现克隆可以实现真正的深克隆。BeanUtilsapache和Spring都提供了bean工具只是这都是浅克隆。3深拷贝和浅拷贝区别是什么浅拷贝仅仅克隆基本类型变量不克隆引用类型变量深克隆既克隆基本类型变量又克隆引用类型变量4代码实例20、throw 和 throws 的区别1throw作用在方法内表示抛出具体异常由方法体内的语句处理一定抛出了异常2throws作用在方法的声明上表示抛出异常由调用者来进行异常处理可能出现异常不一定会发生异常21、final、finally、finalize 有什么区别final可以修饰类变量方法修饰的类不能被继承修饰的变量不能重新赋值修饰的方法不能被重写finally用于抛异常finally代码块内语句无论是否发生异常都会在执行finally常用于一些流的关闭。finalize方法用于垃圾回收。一般情况下不需要我们实现finalize当对象被回收的时候需要释放一些资源比如socket链接在对象初始化时创建整个生命周期内有效那么需要实现finalize方法关闭这个链接。但是当调用finalize方法后并不意味着gc会立即回收该对象所以有可能真正调用的时候对象又不需要回收了然后到了真正要回收的时候因为之前调用过一次这次又不会调用了产生问题。所以不推荐使用finalize方法。22、try-catch-finally 中如果 catch 中 return 了finally 还会执行吗23、常见的异常类有哪些NullPointerException空指针异常SQLException数据库相关的异常IndexOutOfBoundsException数组下角标越界异常FileNotFoundException打开文件失败时抛出IOException当发生某种IO异常时抛出ClassCastException当试图将对象强制转换为不是实例的子类时抛出此异常NoSuchMethodException无法找到某一方法时抛出ArrayStoreException试图将错误类型的对象存储到一个对象数组时抛出的异常NumberFormatException当试图将字符串转换成数字时失败了抛出IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。ArithmeticException当出现异常的运算条件时抛出此异常。例如一个整数“除以零”时抛出此类的一个实例。24、hashcode是什么有什么作用Java中Object有一个方法public native int hashcode();1hashcode()方法的作用hashcode()方法主要配合基于散列的集合一起使用比如HashSet、HashMap、HashTable。当集合需要添加新的对象时先调用这个对象的hashcode()方法得到对应的hashcode值实际上hashmap中会有一个table保存已经存进去的对象的hashcode值如果table中没有改hashcode值则直接存入如果有就调用equals方法与新元素进行比较相同就不存了不同就存入。2equals和hashcode的关系如果equals为truehashcode一定相等如果equals为falsehashcode不一定不相等如果hashcode值相等equals不一定相等如果hashcode值不等equals一定不等3重写equals方法时一定要重写hashcode方法4百度百科hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点例如java.util.Hashtable 提供的哈希表。hashCode 的常规协定是在 Java 应用程序执行期间在同一对象上多次调用 hashCode 方法时必须一致地返回相同的整数前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行该整数无需保持一致。如果根据 equals(Object) 方法两个对象是相等的那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。以下情况不 是必需的如果根据 equals(java.lang.Object) 方法两个对象不相等那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是程序员应该知道为不相等的对象生成不同整数结果可以提高哈希表的性能。实际上由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。这一般是通过将该对象的内部地址转换成一个整数来实现的但是 JavaTM 编程语言不需要这种实现技巧。当equals方法被重写时通常有必要重写 hashCode 方法以维护 hashCode 方法的常规协定该协定声明相等对象必须具有相等的哈希码。5小白解释1.hashcode是用来查找的如果你学过数据结构就应该知道在查找和排序这一章有例如内存中有这样的位置0 1 2 3 4 5 6 7而我有个类这个类有个字段叫ID,我要把这个类存放在以上8个位置之一如果不用hashcode而任意存放那么当查找时就需要到这八个位置里挨个去找或者用二分法一类的算法。但如果用hashcode那就会使效率提高很多。我们这个类中有个字段叫ID,那么我们就定义我们的hashcode为ID8然后把我们的类存放在取得得余数那个位置。比如我们的ID为99除8的余数为1那么我们就把该类存在1这个位置如果ID是13求得的余数是5那么我们就把该类放在5这个位置。这样以后在查找该类时就可以通过ID除 8求余数直接找到存放的位置了。2.但是如果两个类有相同的hashcode怎么办那我们假设上面的类的ID不是唯一的例如9除以8和17除以8的余数都是1那么这是不是合法的回答是可以这样。那么如何判断呢在这个时候就需要定义 equals了。也就是说我们先通过 hashcode来判断两个类是否存放某个桶里但这个桶里可能有很多类那么我们就需要再通过 equals 来在这个桶里找到我们要的类。那么。重写了equals()为什么还要重写hashCode()呢想想你要在一个桶里找东西你必须先要找到这个桶啊你不通过重写hashcode()来找到桶光重写equals()有什么用啊。25、java 中操作字符串都有哪些类它们之间有什么区别1StringString是不可变对象每次对String类型的改变时都会生成一个新的对象。2StringBuilder线程不安全效率高多用于单线程。3StringBuffer线程安全由于加锁的原因效率不如StringBuilder多用于多线程。不频繁的字符串操作使用String操作频繁的情况不建议使用String。StringBuilder StringBuffer String。26、java 中都有哪些引用类型1强引用Java中默认声明的就是强引用比如Object obj new Object(); obj null;只要强引用存在垃圾回收器将永远不会回收被引用的对象。如果想被回收可以将对象置为null2软引用SoftReference在内存足够的时候软引用不会被回收只有在内存不足时系统才会回收软引用对象如果回收了软引用对象之后仍然没有足够的内存才会跑出内存溢出异常。byte[] buff new byte[1024 * 1024]; SoftReferencebyte[] sr new SoftReference(buff);3弱引用WeakReference进行垃圾回收时弱引用就会被回收。4虚引用PhantomReference5引用队列ReferenceQueue引用队列可以与软引用、弱引用、虚引用一起配合使用。当垃圾回收器准备回收一个对象时如果发现它还有引用就会在回收对象之前把这个引用加入到引用队列中。程序可以通过判断引用队列中是否加入了引用来判断被引用的对象是否将要被垃圾回收这样可以在对象被回收之前采取一些必要的措施。27、在 Java 中为什么不允许从静态方法中访问非静态变量静态变量属于类本身在类加载的时候就会分配内存可以通过类名直接访问非静态变量属于类的对象只有在类的对象产生时才会分配内存通过类的实例去访问静态方法也属于类本身但是此时没有类的实例内存中没有非静态变量所以无法调用。28、说说Java Bean的命名规范JavaBean 类必须是一个公共类并将其访问属性设置为 publicJavaBean 类必须有一个空的构造函数类中必须有一个不带参数的公用构造器此构造器也应该通过调用各个特性的设置方法来设置特性的缺省值。一个javaBean类不应有公共实例变量类变量都为private持有值应该通过一组存取方法getXxx 和 setXxx来访问对于每个特性应该有一个带匹配公用 getter 和 setter 方法的专用实例变量。属性为布尔类型可以使用 isXxx() 方法代替 getXxx() 方法。通常属性名是要和 包名、类名、方法名、字段名、常量名作出区别的:首先:必须用英文不要用汉语拼音1包(package)用于将完成不同功能的类分门别类放在不同的目录(包)下包的命名规则将公司域名反转作为包名。比如www.sohu.com 对于包名每个字母都需要小写。比如com.sohu.test;该包下的Test类的全名是com.sohu.Test.Java 。如果定义类的时候没有使用package,那么java就认为我们所定义的类位于默认包里面(default package)。2类首字母大写如果一个类由多个单词构成那么每个单词的首字母都大写而且中间不使用任何的连接符。尽量使用英文。如ConnectionFactory3方法首单词全部小写如果一个方法由多个单词构成那么从第二个单词开始首字母大写不使用连接符。addPerson4字段与方法相同。如ageOfPerson5常量所有单词的字母都是大写如果有多个单词那么使用下划线链接即可。如public static final int AGE_OF_PERSON 20; //通常加上static29、Java Bean 属性命名规范问题分析public class User { private String busName; private String pCount; private Boolean isRunning; //正确的命名方式驼峰式的 public String getBusName() { return busName; } public void setBusName(String busName) { this.busName busName; } //这是什么 public String getpCount() { return pCount; } public void setpCount(String pCount) { this.pCount pCount; } //这个也是不允许的 public Boolean getIsRunning() { return isRunning; } public void setIsRunning(Boolean isRunning) { this.isRunning isRunning; } }1. javabean属性命名尽量使用常规的驼峰式命名规则2. 属性名第一个单词尽量避免使用一个字母如eBook eMail。3. boolean属性名避免使用 “is” 开头的名称4. 随着jdk eclipse spring 等软件版本的不断提高 底版本的出现的问题可能在高版本中解决了 低版本原来正常的代码可能在高版本环境下不再支持。30、什么是 Java 的内存模型?在了解什么是 Java 内存模型之前先了解一下为什么要提出 Java 内存模型。之前提到过并发编程有三大问题CPU 缓存在多核 CPU 的情况下带来了可见性问题操作系统对当前执行线程的切换带来了原子性问题译器指令重排优化带来了有序性问题为了解决并发编程的三大问题提出了 JSR-133新的 Java 内存模型JDK 5 开始使用。简单总结下Java 内存模型是 JVM 的一种规范定义了共享内存在多线程程序中读写操作行为的规范屏蔽了各种硬件和操作系统的访问差异保证了 Java 程序在各种平台下对内存的访问效果一致解决并发问题采用的方式限制处理器优化和使用内存屏障增强了三个同步原语synchronized、volatile、final的内存语义定义了 happens-before 规则31、在 Java 中什么时候用重载什么时候用重写1重载是多态的集中体现在类中要以统一的方式处理不同类型数据的时候可以用重载。2重写的使用是建立在继承关系上的子类在继承父类的基础上增加新的功能可以用重写。3简单总结重载是多样性重写是增强剂目的是提高程序的多样性和健壮性以适配不同场景使用时使用重载进行扩展目的是在不修改原方法及源代码的基础上对方法进行扩展或增强时使用重写生活例子你想吃一碗面我给你提供了拉面炒面刀削面担担面供你选择这是重载你想吃一碗面我不但给你端来了面还给你加了青菜加了鸡蛋这个是重写设计模式cglib实现动态代理核心原理用的就是方法的重写详细解答Java的重载(overload) 最重要的应用场景就是构造器的重载构造器重载后提供多种形参形式的构造器可以应对不同的业务需求加强程序的健壮性和可扩展性比如我们最近学习的Spring源码中的ClassPathXmlApplicationContext它的构造函数使用重载一共提供了10个构造函数这样就为业务的选择提供了多选择性。在应用到方法中时主要是为了增强方法的健壮性和可扩展性比如我们在开发中常用的各种工具类比如我目前工作中的短信工具类SMSUtil, 发短信的方法就会使用重载针对不同业务场景下的不同形参提供短信发送方法这样提高了工具类的扩展性和健壮性。总结重载必须要修改方法(构造器)的形参列表可以修改方法的返回值类型也可以修改方法的异常信息即访问权限使用范围是在同一个类中目的是对方法(构造器)进行功能扩展以应对多业务场景的不同使用需求。提高程序的健壮性和扩展性。java的重写(override) 只要用于子类对父类方法的扩展或修改但是在我们开发中为了避免程序混乱重写一般都是为了方法的扩展比如在cglib方式实现的动态代理中代理类就是继承了目标类对目标类的方法进行重写同时在方法前后进行切面织入。总结方法重写时参数列表返回值得类型是一定不能修改的异常可以减少或者删除但是不能抛出新的异常或者更广的异常方法的访问权限可以降低限制但是不能做更严格的限制。4在里氏替换原则中子类对父类的方法尽量不要重写和重载。我们可以采用final的手段强制来遵循32、举例说明什么情况下会更倾向于使用抽象类而不是接口接口和抽象类都遵循”面向接口而不是实现编码”设计原则它可以增加代码的灵活性可以适应不断变化的需求。下面有几个点可以帮助你回答这个问题在 Java 中你只能继承一个类但可以实现多个接口。所以一旦你继承了一个类你就失去了继承其他类的机会了。接口通常被用来表示附属描述或行为如 Runnable 、 Clonable 、 Serializable 等等因此当你使用抽象类来表示行为时你的类就不能同时是 Runnable 和 Clonable( 注这里的意思是指如果把 Runnable 等实现为抽象类的情况 ) 因为在 Java 中你不能继承两个类但当你使用接口时你的类就可以同时拥有多个不同的行为。在一些对时间要求比较高的应用中倾向于使用抽象类它会比接口稍快一点。如果希望把一系列行为都规范在类继承层次内并且可以更好地在同一个地方进行编码那么抽象类是一个更好的选择。有时接口和抽象类可以一起使用接口中定义函数而在抽象类中定义默认的实现。33、实例化对象有哪几种方式newclone()通过反射机制创建//用 Class.forName方法获取类在调用类的newinstance方法 Class? cls Class.forName(com.dao.User); User u (User)cls.newInstance();序列化反序列化//将一个对象实例化后进行序列化再反序列化也可以获得一个对象远程通信的场景下使用 ObjectOutputStream out new ObjectOutputStream (new FileOutputStream(D:/data.txt)); //序列化对象 out.writeObject(user1); out.close(); //反序列化对象 ObjectInputStream in new ObjectInputStream(new FileInputStream(D:/data.txt)); User user2 (User) in.readObject(); System.out.println(反序列化user user2); in.close();34、byte类型1271等于多少byte的范围是-128~127。字节长度为8位最左边的是符号位而127的二进制为01111111所以执行1操作时01111111变为10000000。大家知道计算机中存储负数存的是补码的兴衰。左边第一位为符号位。那么负数的补码转换成十进制如下一个数如果为正则它的原码、反码、补码相同一个正数的补码将其转化为十进制可以直接转换。已知一个负数的补码将其转换为十进制数步骤如下先对各位取反将其转换为十进制数加上负号再减去1例如10000000最高位是1是负数①对各位取反得01111111转换为十进制就是127加上负号得-127再减去1得-12835、Java 容器都有哪些1Collection① setHashSet、TreeSet② listArrayList、LinkedList、Vector2MapHashMap、HashTable、TreeMap36、Collection 和 Collections 有什么区别1Collection是最基本的集合接口Collection派生了两个子接口list和set分别定义了两种不同的存储方式。2Collections是一个包装类它包含各种有关集合操作的静态方法对集合的搜索、排序、线程安全化等。此类不能实例化就像一个工具类服务于Collection框架。37、list与Set区别1List简介实际上有两种List一种是基本的ArrayList,其优点在于随机访问元素另一种是LinkedList,它并不是为快速随机访问设计的而是快速的插入或删除。ArrayList由数组实现的List。允许对元素进行快速随机访问但是向List中间插入与移除元素的速度很慢。LinkedList 对顺序访问进行了优化向List中间插入与删除的开销并不大。随机访问则相对较慢。还具有下列方 法addFirst(), addLast(), getFirst(), getLast(), removeFirst() 和 removeLast(), 这些方法 (没有在任何接口或基类中定义过)使得LinkedList可以当作堆栈、队列和双向队列使用。2Set简介Set具有与Collection完全一样的接口因此没有任何额外的功能。实际上Set就是Collection,只是行为不同。这是继承与多态思想的典型应用表现不同的行为。Set不保存重复的元素(至于如何判断元素相同则较为负责)Set : 存入Set的每个元素都必须是唯一的因为Set不保存重复元素。加入Set的元素必须定义equals()方法以确保对象的唯一性。Set与Collection有完全一样的接口。Set接口不保证维护元素的次序。HashSet为快速查找设计的Set。存入HashSet的对象必须定义hashCode()。TreeSet 保存次序的Set, 底层为树结构。使用它可以从Set中提取有序的序列。3list与Set区别① List,Set都是继承自Collection接口② List特点元素有放入顺序元素可重复 Set特点元素无放入顺序元素不可重复重复元素会覆盖掉元素虽然无放入顺序但是元素在set中的位置是有该元素的HashCode决定的其位置其实是固定的加入Set 的Object必须定义equals()方法 另外list支持for循环也就是通过下标来遍历也可以用迭代器但是set只能用迭代因为他无序无法用下标来取得想要的值。③ Set和List对比Set检索元素效率低下删除和插入效率高插入和删除不会引起元素位置改变。List和数组类似List可以动态增长查找元素效率高插入删除元素效率低因为会引起其他元素位置改变。38、HashMap 和 Hashtable 有什么区别HashMap是线程不安全的HashTable是线程安全的HashMap中允许键和值为nullHashTable不允许HashMap的默认容器是16为2倍扩容HashTable默认是11为2倍1扩容39、说一下 HashMap 的实现原理1简介HashMap基于map接口元素以键值对方式存储允许有null值HashMap是线程不安全的。2基本属性初始化大小默认162倍扩容负载因子0.75初始化的默认数组sizethreshold。判断是否需要调整hashmap容量3HashMap的存储结构JDK1.7中采用数组链表的存储形式。HashMap采取Entry数组来存储key-value每一个键值对组成了一个Entry实体Entry类时机上是一个单向的链表结构它具有next指针指向下一个Entry实体以此来解决Hash冲突的问题。HashMap实现一个内部类Entry重要的属性有hash、key、value、next。JDK1.8中采用数据链表红黑树的存储形式。当链表长度超过阈值8时将链表转换为红黑树。在性能上进一步得到提升。40、set有哪些实现类1HashSetHashSet是set接口的实现类set下面最主要的实现类就是HashSet也就是用的最多的此外还有LinkedHashSet和TreeSet。HashSet是无序的、不可重复的。通过对象的hashCode和equals方法保证对象的唯一性。HashSet内部的存储结构是哈希表是线程不安全的。2TreeSetTreeSet对元素进行排序的方式元素自身具备比较功能需要实现Comparable接口并覆盖compareTo方法。元素自身不具备比较功能需要实现Comparator接口并覆盖compare方法。3LinkedHashSetLinkedHashSet是一种有序的Set集合即其元素的存入和输出的顺序是相同的。41、说一下 HashSet 的实现原理HashSet实际上是一个HashMap实例数据存储结构都是数组链表。HashSet是基于HashMap实现的HashSet中的元素都存放在HashMap的key上面而value都是一个统一的对象PRESENT。private static final Object PRESENT new Object();HashSet中add方法调用的是底层HashMap中的put方法put方法要判断插入值是否存在而HashSet的add方法首先判断元素是否存在如果存在则插入如果不存在则不插入这样就保证了HashSet中不存在重复值。通过对象的hashCode和equals方法保证对象的唯一性。42、ArrayList 和 LinkedList 的区别是什么ArrayList是动态数组的数据结构实现查找和遍历的效率较高LinkedList 是双向链表的数据结构增加和删除的效率较高43、如何实现数组和 List 之间的转换String[] arr {zs,ls,ww}; ListString list Arrays.asList(arr); System.out.println(list); ArrayListString list1 new ArrayListString(); list1.add(张三); list1.add(李四); list1.add(王五); String[] arr1 list1.toArray(new String[list1.size()]); System.out.println(arr1); for(int i 0; i arr1.length; i){ System.out.println(arr1[i]); }44、在 Queue 中 poll()和 remove()有什么区别1offer()和add()区别增加新项时如果队列满了add会抛出异常offer返回false。2poll()和remove()区别poll()和remove()都是从队列中删除第一个元素remove抛出异常poll返回null。3peek()和element区别peek()和element用于查询队列头部元素为空时element抛出异常peek返回null。45、哪些集合类是线程安全的Vector就比Arraylist多了个同步化机制线程安全。Stack栈也是线程安全的继承于Vector。Hashtable就比Hashmap多了个线程安全。ConcurrentHashMap:是一种高效但是线程安全的集合。46、迭代器 Iterator 是什么为了方便的处理集合中的元素,Java中出现了一个对象,该对象提供了一些方法专门处理集合中的元素.例如删除和获取集合中的元素.该对象就叫做迭代器(Iterator)。47、Iterator 怎么使用有什么特点Iterator 接口源码中的方法java.lang.Iterable 接口被 java.util.Collection 接口继承java.util.Collection 接口的 iterator() 方法返回一个 Iterator 对象next() 方法获得集合中的下一个元素hasNext() 检查集合中是否还有元素remove() 方法将迭代器新返回的元素删除48、Iterator 和 ListIterator 有什么区别1ListIterator 继承 Iterator2ListIterator 比 Iterator多方法add(E e) 将指定的元素插入列表插入位置为迭代器当前位置之前set(E e) 迭代器返回的最后一个元素替换参数ehasPrevious() 迭代器当前位置反向遍历集合是否含有元素previous() 迭代器当前位置反向遍历集合下一个元素previousIndex() 迭代器当前位置反向遍历集合返回下一个元素的下标nextIndex() 迭代器当前位置返回下一个元素的下标3使用范围不同Iterator可以迭代所有集合ListIterator 只能用于List及其子类ListIterator 有 add 方法可以向 List 中添加对象Iterator 不能ListIterator 有 hasPrevious() 和 previous() 方法可以实现逆向遍历Iterator不可以ListIterator 有 nextIndex() 和previousIndex() 方法可定位当前索引的位置Iterator不可以ListIterator 有 set()方法可以实现对 List 的修改Iterator 仅能遍历不能修改。49、怎么确保一个集合不能被修改我们很容易想到用final关键字进行修饰我们都知道final关键字可以修饰类方法成员变量final修饰的类不能被继承final修饰的方法不能被重写final修饰的成员变量必须初始化值如果这个成员变量是基本数据类型表示这个变量的值是不可改变的如果说这个成员变量是引用类型则表示这个引用的地址值是不能改变的但是这个引用所指向的对象里面的内容还是可以改变的。那么我们怎么确保一个集合不能被修改首先我们要清楚集合map,set,list…都是引用类型所以我们如果用final修饰的话集合里面的内容还是可以修改的。我们可以做一个实验可以看到我们用final关键字定义了一个map集合这时候我们往集合里面传值第一个键值对1,1我们再修改后可以把键为1的值改为100说明我们是可以修改map集合的值的。那我们应该怎么做才能确保集合不被修改呢我们可以采用Collections包下的unmodifiableMap方法通过这个方法返回的map,是不可以修改的。他会报 java.lang.UnsupportedOperationException错。同理Collections包也提供了对list和set集合的方法。Collections.unmodifiableList(List)Collections.unmodifiableSet(Set)50、队列和栈是什么有什么区别1队列先进先出栈先进后出。2遍历数据速度不同。栈只能从头部取数据 也就最先放入的需要遍历整个栈最后才能取出来而且在遍历数据的时候还得为数据开辟临时空间保持数据在遍历前的一致性队列则不同他基于地址指针进行遍历而且可以从头或尾部开始遍历但不能同时遍历无需开辟临时空间因为在遍历的过程中不影像数据结构速度要快的多。51、Java8开始ConcurrentHashMap,为什么舍弃分段锁ConcurrentHashMap的原理是引用了内部的 Segment ( ReentrantLock ) 分段锁保证在操作不同段 map 的时候 可以并发执行 操作同段 map 的时候进行锁的竞争和等待。从而达到线程安全 且效率大于 synchronized。但是在 Java 8 之后 JDK 却弃用了这个策略重新使用了 synchronizedCAS。弃用原因通过 JDK 的源码和官方文档看来 他们认为的弃用分段锁的原因由以下几点加入多个分段锁浪费内存空间。生产环境中 map 在放入时竞争同一个锁的概率非常小分段锁反而会造成更新等操作的长时间等待。为了提高 GC 的效率新的同步方案既然弃用了分段锁 那么一定由新的线程安全方案 我们来看看源码是怎么解决线程安全的呢源码保留了segment 代码 但并没有使用。52、ConcurrentHashMap(JDK1.8)为什么要使用synchronized而不是如ReentranLock这样的可重入锁我想从下面几个角度讨论这个问题1锁的粒度首先锁的粒度并没有变粗甚至变得更细了。每当扩容一次ConcurrentHashMap的并发度就扩大一倍。2Hash冲突JDK1.7中ConcurrentHashMap从过二次hash的方式Segment - HashEntry能够快速的找到查找的元素。在1.8中通过链表加红黑树的形式弥补了put、get时的性能差距。JDK1.8中在ConcurrentHashmap进行扩容时其他线程可以通过检测数组中的节点决定是否对这条链表红黑树进行扩容减小了扩容的粒度提高了扩容的效率。下面是我对面试中的那个问题的一下看法。为什么是synchronized而不是ReentranLock1减少内存开销假设使用可重入锁来获得同步支持那么每个节点都需要通过继承AQS来获得同步支持。但并不是每个节点都需要获得同步支持的只有链表的头节点红黑树的根节点需要同步这无疑带来了巨大内存浪费。2获得JVM的支持可重入锁毕竟是API这个级别的后续的性能优化空间很小。synchronized则是JVM直接支持的JVM能够在运行时作出相应的优化措施锁粗化、锁消除、锁自旋等等。这就使得synchronized能够随着JDK版本的升级而不改动代码的前提下获得性能上的提升。53、concurrentHashMap和HashTable有什么区别concurrentHashMap融合了hashmap和hashtable的优势hashmap是不同步的但是单线程情况下效率高hashtable是同步的同步情况下保证程序执行的正确性。但hashtable每次同步执行的时候都要锁住整个结构如下图concurrentHashMap锁的方式是细粒度的。concurrentHashMap将hash分为16个桶默认值诸如get、put、remove等常用操作只锁住当前需要用到的桶。concurrentHashMap的读取并发因为读取的大多数时候都没有锁定所以读取操作几乎是完全的并发操作只是在求size时才需要锁定整个hash。而且在迭代时concurrentHashMap使用了不同于传统集合的快速失败迭代器的另一种迭代方式弱一致迭代器。在这种方式中当iterator被创建后集合再发生改变就不会抛出ConcurrentModificationException取而代之的是在改变时new新的数据而不是影响原来的数据iterator完成后再讲头指针替代为新的数据这样iterator时使用的是原来的数据。54、HasmMap和HashSet的区别1先了解一下HashCodeJava中的集合有两类一类是List一类是Set。List元素有序可以重复Set元素无序不可重复要想保证元素的不重复拿什么来判断呢这就是Object.equals方法了。如果元素有很多增加一个元素就要判断n次吗显然不现实于是Java采用了哈希表的原理。哈希算法也称为散列算法是将数据依特定算法直接指定到一根地址上初学者可以简单的理解为HashCode方法返回的就是对象存储的物理位置实际上并不是。这样一来当集合添加新的元素时先调用这个元素的hashcode()方法就一下子能定位到他应该放置的物理位置上。如果这个位置上没有元素他就可以直接存储在这个位置上不用再进行任何比较了。如果这个位置上有元素就调用它的equals方法与新元素进行比较想同的话就不存了不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际上调用equals方法的次数就大大降低了几乎只需要一两次。简而言之在集合查找时hashcode能大大降低对象比较次数提高查找效率。Java对象的equals方法和hashCode方法时这样规定的相等的对象就必须具有相等的hashcode。如果两个对象的hashcode相同他们并不一定相同。如果两个对象的hashcode相同他们并不一定相同。如果两个Java对象A和BA和B不相等但是A和B的哈希码相等将A和B都存入HashMap时会发生哈希冲突也就是A和B存放在HashMap内部数组的位置索引相同这时HashMap会在该位置建立一个链接表将A和B串起来放在该位置显然该情况不违反HashMap的使用规则是允许的。当然哈希冲突越少越好尽量采用好的哈希算法避免哈希冲突。equals()相等的两个对象hashcode()一定相等equals()不相等的两个对象却并不能证明他们的hashcode()不相等。2HashMap和HashSet的区别55、请谈谈 ReadWriteLock 和 StampedLockReadWriteLock包括两种子锁1ReadWriteLockReadWriteLock 可以实现多个读锁同时进行但是读与写和写于写互斥只能有一个写锁线程在进行。2StampedLockStampedLock是Jdk在1.8提供的一种读写锁相比较ReentrantReadWriteLock性能更好因为ReentrantReadWriteLock在读写之间是互斥的使用的是一种悲观策略在读线程特别多的情况下会造成写线程处于饥饿状态虽然可以在初始化的时候设置为true指定为公平但是吞吐量又下去了而StampedLock是提供了一种乐观策略更好的实现读写分离并且吞吐量不会下降。StampedLock包括三种锁1写锁writeLockwriteLock是一个独占锁写锁当一个线程获得该锁后其他请求读锁或者写锁的线程阻塞 获取成功后会返回一个stamp凭据变量来表示该锁的版本在释放锁时调用unlockWrite方法传递stamp参数。提供了非阻塞式获取锁tryWriteLock。2悲观读锁readLockreadLock是一个共享读锁在没有线程获取写锁情况下多个线程可以获取该锁。如果有写锁获取那么其他线程请求读锁会被阻塞。悲观读锁会认为其他线程可能要对自己操作的数据进行修改所以需要先对数据进行加锁这是在读少写多的情况下考虑的。请求该锁成功后会返回一个stamp值在释放锁时调用unlockRead方法传递stamp参数。提供了非阻塞式获取锁方法tryWriteLock。3乐观读锁tryOptimisticReadtryOptimisticRead相对比悲观读锁在操作数据前并没有通过CAS设置锁的状态如果没有线程获取写锁则返回一个非0的stamp变量获取该stamp后在操作数据前还需要调用validate方法来判断期间是否有线程获取了写锁如果是返回值为0则有线程获取写锁如果不是0则可以使用stamp变量的锁来操作数据。由于tryOptimisticRead并没有修改锁状态所以不需要释放锁。这是读多写少的情况下考虑的不涉及CAS操作所以效率较高在保证数据一致性上需要复制一份要操作的变量到方法栈中并且在操作数据时可能其他写线程已经修改了数据而我们操作的是方法栈里面的数据也就是一个快照所以最多返回的不是最新的数据但是一致性得到了保证。56、线程的run()和start()有什么区别每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的run()方法称为线程体。通过调用Thread类的start()方法来启动一个线程。start() 方法用于启动线程run() 方法用于执行线程的运行时代码。run() 可以重复调用而 start() 只能调用一次。start()方法来启动一个线程真正实现了多线程运行。调用start()方法无需等待run方法体代码执行完毕可以直接继续执行其他的代码 此时线程是处于就绪状态并没有运行。 然后通过此Thread类调用方法run()来完成其运行状态 run()方法运行结束 此线程终止。然后CPU再调度其它线程。run()方法是在本线程里的只是线程里的一个函数而不是多线程的。 如果直接调用run()其实就相当于是调用了一个普通函数而已直接待用run()方法必须等待run()方法执行完毕才能执行下面的代码所以执行路径还是只有一条根本就没有线程的特征所以在多线程执行时要使用start()方法而不是run()方法。57、为什么我们调用 start() 方法时会执行 run() 方法为什么我们不能直接调用 run() 方法这是另一个非常经典的 java 多线程面试问题而且在面试中会经常被问到。很简单但是很多人都会答不上来new 一个 Thread线程进入了新建状态。调用 start() 方法会启动一个线程并使线程进入了就绪状态当分配到时间片后就可以开始运行了。 start() 会执行线程的相应准备工作然后自动执行 run() 方法的内容这是真正的多线程工作。而直接执行 run() 方法会把 run 方法当成一个 main 线程下的普通方法去执行并不会在某个线程中执行它所以这并不是多线程工作。总结 调用 start 方法方可启动线程并使线程进入就绪状态而 run 方法只是 thread 的一个普通方法调用还是在主线程里执行。58、Synchronized 用过吗其原理是什么1可重入性synchronized的锁对象中有一个计数器recursions变量会记录线程获得几次锁可重入的好处可以避免死锁可以让我们更好的封装代码synchronized是可重入锁每部锁对象会有一个计数器记录线程获取几次锁在执行完同步代码块时计数器的数量会-1直到计数器的数量为0就释放这个锁。2不可中断性一个线程获得锁后另一个线程想要获得锁必须处于阻塞或等待状态如果第一个线程不释放锁第二个线程会一直阻塞或等待不可被中断synchronized 属于不可被中断Lock lock方法是不可中断的Lock tryLock方法是可中断的59、JVM 对 Java 的原生锁做了哪些优化1自旋锁在线程进行阻塞的时候先让线程自旋等待一段时间可能这段时间其它线程已经解锁这时就无需让线程再进行阻塞操作了。自旋默认次数是10次。2自适应自旋锁自旋锁的升级自旋的次数不再固定由前一次自旋次数和锁的拥有者的状态决定。3锁消除在动态编译同步代码块的时候JIT编译器借助逃逸分析技术来判断锁对象是否只被一个线程访问而没有其他线程这时就可以取消锁了。4、锁粗化当JIT编译器发现一系列的操作都对同一个对象反复加锁解锁甚至加锁操作出现在循环中此时会将加锁同步的范围粗化到整个操作系列的外部。锁粒度不要锁住一些无关的代码。锁粗化可以一次性执行完的不要多次加锁执行。60、为什么 wait(), notify()和 notifyAll()必须在同步方法或者同步块中被调用Java中任何对象都可以作为锁并且 wait()notify()等方法用于等待对象的锁或者唤醒线程在 Java 的线程中并没有可供任何对象使用的锁所以任意对象调用方法一定定义在Object类中。wait(), notify()和 notifyAll()这些方法在同步代码块中调用有的人会说既然是线程放弃对象锁那也可以把wait()定义在Thread类里面啊新定义的线程继承于Thread类也不需要重新定义wait()方法的实现。然而这样做有一个非常大的问题一个线程完全可以持有很多锁你一个线程放弃锁的时候到底要放弃哪个锁当然了这种设计并不是不能实现只是管理起来更加复杂。综上所述wait()、notify()和notifyAll()方法要定义在Object类中。61、Java 如何实现多线程之间的通讯和协作可以通过中断 和 共享变量的方式实现线程间的通讯和协作比如说最经典的生产者-消费者模型当队列满时生产者需要等待队列有空间才能继续往里面放入商品而在等待的期间内生产者必须释放对临界资源即队列的占用权。因为生产者如果不释放对临界资源的占用权那么消费者就无法消费队列中的商品就不会让队列有空间那么生产者就会一直无限等待下去。因此一般情况下当队列满时会让生产者交出对临界资源的占用权并进入挂起状态。然后等待消费者消费了商品然后消费者通知生产者队列有空间了。同样地当队列空时消费者也必须等待等待生产者通知它队列中有商品了。这种互相通信的过程就是线程间的协作。Java中线程通信协作的最常见的两种方式1、syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()2、ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()线程间直接的数据交换通过管道进行线程间通信1字节流2字符流62、Thread 类中的 yield 方法有什么作用yield()应该做的是让当前运行线程回到可运行状态以允许具有相同优先级的其他线程获得运行机会。因此使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是实际中无法保证yield()达到让步目的因为让步的线程还有可能被线程调度程序再次选中。结论yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下yield()将导致线程从运行状态转到可运行状态但有可能没有效果。63、为什么说 Synchronized 是非公平锁当锁被释放后任何一个线程都有机会竞争得到锁这样做的目的是提高效率但缺点是可能产生线程饥饿现象。64、请谈谈 volatile 有什么特点为什么它能保证变量对所有线程的可见性volatile只能作用于变量保证了操作可见性和有序性不保证原子性。在Java的内存模型中分为主内存和工作内存Java内存模型规定所有的变量存储在主内存中每条线程都有自己的工作内存。主内存和工作内存之间的交互分为8个原子操作lockunlockreadloadassignusestorewritevolatile修饰的变量只有对volatile进行assign操作才可以load只有load才可以use这样就保证了在工作内存操作volatile变量都会同步到主内存中。65、为什么说 Synchronized 是一个悲观锁乐观锁的实现原理又是什么什么是 CAS它有什么特性Synchronized的并发策略是悲观的不管是否产生竞争任何数据的操作都必须加锁。乐观锁的核心是CASCAS包括内存值、预期值、新值只有当内存值等于预期值时才会将内存值修改为新值。66、乐观锁一定就是好的吗乐观锁认为对一个对象的操作不会引发冲突所以每次操作都不进行加锁只是在最后提交更改时验证是否发生冲突如果冲突则再试一遍直至成功为止这个尝试的过程称为自旋。乐观锁没有加锁但乐观锁引入了ABA问题此时一般采用版本号进行控制也可能产生自旋次数过多问题此时并不能提高效率反而不如直接加锁的效率高只能保证一个对象的原子性可以封装成对象再进行CAS操作67、请尽可能详尽地对比下 Synchronized 和 ReentrantLock 的异同。1相似点它们都是阻塞式的同步也就是说一个线程获得了对象锁进入代码块其它访问该同步块的线程都必须阻塞在同步代码块外面等待而进行线程阻塞和唤醒的代码是比较高的。2功能区别Synchronized是java语言的关键字是原生语法层面的互斥需要JVM实现ReentrantLock 是JDK1.5之后提供的API层面的互斥锁需要lock和unlock()方法配合try/finally代码块来完成。Synchronized使用较ReentrantLock 便利一些锁的细粒度和灵活性ReentrantLock强于Synchronized3性能区别Synchronized引入偏向锁自旋锁之后两者的性能差不多在这种情况下官方建议使用Synchronized。① SynchronizedSynchronized会在同步块的前后分别形成monitorenter和monitorexit两个字节码指令。在执行monitorenter指令时首先要尝试获取对象锁。如果这个对象没被锁定或者当前线程已经拥有了那个对象锁把锁的计数器1相应的执行monitorexit时计数器-1当计数器为0时锁就会被释放。如果获取锁失败当前线程就要阻塞知道对象锁被另一个线程释放为止。② ReentrantLockReentrantLock是java.util.concurrent包下提供的一套互斥锁相比SynchronizedReentrantLock类提供了一些高级功能主要有如下三项等待可中断持有锁的线程长期不释放的时候正在等待的线程可以选择放弃等待这相当于Synchronized避免出现死锁的情况。通过lock.lockInterruptibly()来实现这一机制公平锁多个线程等待同一个锁时必须按照申请锁的时间顺序获得锁Synchronized锁是非公平锁ReentrantLock默认也是非公平锁可以通过参数true设为公平锁但公平锁表现的性能不是很好锁绑定多个条件一个ReentrantLock对象可以同时绑定多个对象。ReentrantLock提供了一个Condition条件类用来实现分组唤醒需要唤醒的线程们而不是像Synchronized要么随机唤醒一个线程要么唤醒全部线程。68、ReentrantLock 是如何实现可重入性的1什么是可重入性一个线程持有锁时当其他线程尝试获取该锁时会被阻塞而这个线程尝试获取自己持有锁时如果成功说明该锁是可重入的反之则不可重入。2synchronized是如何实现可重入性synchronized关键字经过编译后会在同步块的前后分别形成monitorenter和monitorexit两个字节码指令。每个锁对象内部维护一个计数器该计数器初始值为0表示任何线程都可以获取该锁并执行相应的方法。根据虚拟机规范要求在执行monitorenter指令时首先要尝试获取对象的锁如果这个对象没有被锁定或者当前线程已经拥有了对象的锁把锁的计数器1相应的在执行monitorexit指令后锁计数器-1当计数器为0时锁就被释放。如果获取对象锁失败那当前线程就要阻塞等待直到对象锁被另一个线程释放为止。3ReentrantLock如何实现可重入性ReentrantLock使用内部类Sync来管理锁所以真正的获取锁是由Sync的实现类控制的。Sync有两个实现分别为NonfairSync非公公平锁和FairSync公平锁。Sync通过继承AQS实现在AQS中维护了一个private volatile int state来计算重入次数避免频繁的持有释放操作带来的线程问题。4ReentrantLock代码实例// Sync继承于AQS abstract static class Sync extends AbstractQueuedSynchronizer { ... } // ReentrantLock默认是非公平锁 public ReentrantLock() { sync new NonfairSync(); } // 可以通过向构造方法中传true来实现公平锁 public ReentrantLock(boolean fair) { sync fair ? new FairSync() : new NonfairSync(); }protected final boolean tryAcquire(int acquires) { // 当前想要获取锁的线程 final Thread current Thread.currentThread(); // 当前锁的状态 int c getState(); // state 0 此时此刻没有线程持有锁 if (c 0) { // 虽然此时此刻锁是可以用的但是这是公平锁既然是公平就得讲究先来后到 // 看看有没有别人在队列中等了半天了 if (!hasQueuedPredecessors() // 如果没有线程在等待那就用CAS尝试一下成功了就获取到锁了 // 不成功的话只能说明一个问题就在刚刚几乎同一时刻有个线程抢先了 _ // 因为刚刚还没人的我判断过了 compareAndSetState(0, acquires)) { // 到这里就是获取到锁了标记一下告诉大家现在是我占用了锁 setExclusiveOwnerThread(current); return true; } } // 会进入这个else if分支说明是重入了需要操作statestate1 // 这里不存在并发问题 else if (current getExclusiveOwnerThread()) { int nextc c acquires; if (nextc 0) throw new Error(Maximum lock count exceeded); setState(nextc); return true; } // 如果到这里说明前面的if和else if都没有返回true说明没有获取到锁 return false; }5代码分析当一个线程在获取锁过程中先判断state的值是否为0如果是表示没有线程持有锁就可以尝试获取锁。当state的值不为0时表示锁已经被一个线程占用了这时会做一个判断currentgetExclusiveOwnerThread()这个方法返回的是当前持有锁的线程这个判断是看当前持有锁的线程是不是自己如果是自己那么将state的值1表示重入返回即可。69、什么是锁消除和锁粗化1锁消除所消除就是虚拟机根据一个对象是否真正存在同步情况若不存在同步情况则对该对象的访问无需经过加锁解锁的操作。比如StringBuffer的append方法因为append方法需要判断对象是否被占用而如果代码不存在锁竞争那么这部分的性能消耗是无意义的。于是虚拟机在即时编译的时候就会将上面的代码进行优化也就是锁消除。Override public synchronized StringBuffer append(String str) { toStringCache null; super.append(str); return this; }从源码可以看出append方法用了 synchronized关键字它是线程安全的。但我们可能仅在线程内部把StringBuffer当做局部变量使用StringBuffer仅在方法内作用域有效不存在线程安全的问题这时我们可以通过编译器将其优化将锁消除前提是Java必须运行在server模式同时必须开启逃逸分析-server -XX:DoEscapeAnalysis -XX:EliminateLocks 其中DoEscapeAnalysis表示开启逃逸分析EliminateLocks表示锁消除。public static String createStringBuffer(String str1, String str2) { StringBuffer sBuf new StringBuffer(); sBuf.append(str1);// append方法是同步操作 sBuf.append(str2); return sBuf.toString(); }逃逸分析比如上面的代码它要看sBuf是否可能逃出它的作用域如果将sBuf作为方法的返回值进行返回那么它在方法外部可能被当作一个全局对象使用就有可能发生线程安全问题这时就可以说sBuf这个对象发生逃逸了因而不应将append操作的锁消除但我们上面的代码没有发生锁逃逸锁消除就可以带来一定的性能提升。2锁粗化锁的请求、同步、释放都会消耗一定的系统资源如果高频的锁请求反而不利于系统性能的优化锁粗化就是把多次的锁请求合并成一个请求扩大锁的范围降低锁请求、同步、释放带来的性能损耗。70、跟 Synchronized 相比可重入锁 ReentrantLock 其实现原理有什么不同1都是可重入锁2ReentrantLock内部是实现了SyncSync继承于AQS抽象类。Sync有两个实现一个是公平锁一个是非公平锁通过构造函数定义。AQS中维护了一个state来计算重入次数避免频繁的持有释放操作带来的线程问题。3ReentrantLock只能定义代码块而Synchronized可以定义方法和代码块4、Synchronized是JVM的一个内部关键字ReentrantLock是JDK1.5之后引入的一个API层面的互斥锁5、Synchronized实现自动的加锁、释放锁ReentrantLock需要手动加锁和释放锁中间可以暂停6、Synchronized由于引进了偏向锁和自旋锁所以性能上和ReentrantLock差不多但操作上方便很多所以优先使用Synchronized。71、那么请谈谈 AQS 框架是怎么回事儿1AQS是AbstractQueuedSynchronizer的缩写它提供了一个FIFO队列可以看成是一个实现同步锁的核心组件。AQS是一个抽象类主要通过继承的方式来使用它本身没有实现任何的同步接口仅仅是定义了同步状态的获取和释放的方法来提供自定义的同步组件。2AQS的两种功能独占锁和共享锁3AQS的内部实现AQS的实现依赖内部的同步队列也就是FIFO的双向队列如果当前线程竞争失败那么AQS会把当前线程以及等待状态信息构造成一个Node加入到同步队列中同时再阻塞该线程。当获取锁的线程释放锁以后会从队列中唤醒一个阻塞的节点线程。AQS队列内部维护的是一个FIFO的双向链表这种结构的特点是每个数据结构都有两个指针分别指向直接的后继节点和直接前驱节点。所以双向链表可以从任意一个节点开始很方便的范文前驱和后继节点。每个Node其实是由线程封装当线程争抢锁失败后会封装成Node加入到AQS队列中。72、AQS 对资源的共享方式AQS定义两种资源共享方式1Exclusive独占只有一个线程能执行如ReentrantLock。又可分为公平锁和非公平锁公平锁按照线程在队列中的排队顺序先到者先拿到锁非公平锁当线程要获取锁时无视队列顺序直接去抢锁谁抢到就是谁的2Share共享多个线程可同时执行如Semaphore/CountDownLatch。Semaphore、CountDownLatch、 CyclicBarrier、ReadWriteLock 我们都会在后面讲到。ReentrantReadWriteLock 可以看成是组合式因为ReentrantReadWriteLock也就是读写锁允许多个线程同时对某一资源进行读。不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源 state 的获取与释放方式即可至于具体线程等待队列的维护如获取资源失败入队/唤醒出队等AQS已经在顶层实现好了。73、如何让 Java 的线程彼此同步synchronizedvolatileReenreantLock使用局部变量实现线程同步74、你了解过哪些同步器请分别介绍下。1Semaphore同步器特征经典的信号量通过计数器控制对共享资源的访问Semaphore(int count):创建拥有count个许可证的信号量acquire()/acquire(int num) : 获取1/num个许可证release/release(int num) : 释放1/num个许可证2CountDownLatch同步器特征必须发生指定数量的事件后才可以继续运行(比如赛跑比赛裁判喊出3,2,1之后大家才同时跑)CountDownLatch(int count):必须发生count个数量才可以打开锁存器await:等待锁存器countDown:触发事件3CyclicBarrier同步器特征适用于只有多个线程都到达预定点时才可以继续执行(比如斗地主需要等齐三个人才开始)CyclicBarrier(int num) :等待线程的数量CyclicBarrier(int num, Runnable action) :等待线程的数量以及所有线程到达后的操作await() : 到达临界点后暂停线程4交换器(Exchanger)同步器5Phaser同步器75、Java 中的线程池是如何实现的创建一个阻塞队列来容纳任务在第一次执行任务时创建足够多的线程并处理任务之后每个工作线程自动从任务队列中获取线程直到任务队列中任务为0为止此时线程处于等待状态一旦有工作任务加入任务队列中即刻唤醒工作线程进行处理实现线程的可复用性。线程池一般包括四个基本组成部分1线程池管理器用于创建线程池销毁线程池添加新任务。2工作线程线程池中线程可循环执行任务在没有任务时处于等待状态。3任务队列用于存放没有处理的任务一种缓存机制。4任务接口每个任务必须实现的接口供工作线程调度任务的执行主要规定了任务的开始和收尾工作和任务的状态。76、创建线程池的几个核心构造参数// Java线程池的完整构造函数 public ThreadPoolExecutor( int corePoolSize, // 线程池长期维持的最小线程数即使线程处于Idle状态也不会回收。 int maximumPoolSize, // 线程数的上限 long keepAliveTime, // 线程最大生命周期。 TimeUnit unit, //时间单位 BlockingQueueRunnable workQueue, //任务队列。当线程池中的线程都处于运行状态而此时任务数量继续增加则需要一个容器来容纳这些任务这就是任务队列。 ThreadFactory threadFactory, // 线程工厂。定义如何启动一个线程可以设置线程名称并且可以确认是否是后台线程等。 RejectedExecutionHandler handler // 拒绝任务处理器。由于超出线程数量和队列容量而对继续增加的任务进行处理的程序。 )78、volatile 关键字的作用对于可见性Java 提供了 volatile 关键字来保证可见性和禁止指令重排。 volatile 提供 happens-before 的保证确保一个线程的修改能对其他线程是可见的。当一个共享变量被 volatile 修饰时它会保证修改的值会立即被更新到主存当有其他线程需要读取时它会去内存中读取新值。从实践角度而言volatile 的一个重要作用就是和 CAS 结合保证了原子性详细的可以参见 java.util.concurrent.atomic 包下的类比如 AtomicInteger。volatile 常用于多线程环境下的单次操作(单次读或者单次写)。79、既然 volatile 能够保证线程间的变量可见性是不是就意味着基于 volatile 变量的运算就是并发安全的volatile修饰的变量在各个线程的工作内存中不存在一致性的问题在各个线程工作的内存中volatile修饰的变量也会存在不一致的情况但是由于每次使用之前都会先刷新主存中的数据到工作内存执行引擎看不到不一致的情况因此可以认为不存在不一致的问题但是java的运算并非原子性的操作导致volatile在并发下并非是线程安全的。80、ThreadLocal 是什么有哪些使用场景ThreadLocal 是一个本地线程副本变量工具类在每个线程中都创建了一个 ThreadLocalMap 对象简单说 ThreadLocal 就是一种以空间换时间的做法每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。通过这种方式避免资源在多线程间共享。原理线程局部变量是局限于线程内部的变量属于线程自身所有不在多个线程间共享。Java提供ThreadLocal类来支持线程局部变量是一种实现线程安全的方式。但是在管理环境下如 web 服务器使用线程局部变量的时候要特别小心在这种情况下工作线程的生命周期比任何应用变量的生命周期都要长。任何线程局部变量一旦在工作完成后没有释放Java 应用就存在内存泄露的风险。经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作不会出现 A 线程关了 B线程正在使用的 Connection 还有 Session 管理 等问题。81、请谈谈 ThreadLocal 是怎么解决并发安全的在java程序中常用的有两种机制来解决多线程并发问题一种是sychronized方式通过锁机制一个线程执行时让另一个线程等待是以时间换空间的方式来让多线程串行执行。而另外一种方式就是ThreadLocal方式通过创建线程局部变量以空间换时间的方式来让多线程并行执行。两种方式各有优劣适用于不同的场景要根据不同的业务场景来进行选择。在spring的源码中就使用了ThreadLocal来管理连接在很多开源项目中都经常使用ThreadLocal来控制多线程并发问题因为它足够的简单我们不需要关心是否有线程安全问题因为变量是每个线程所特有的。82、很多人都说要慎用 ThreadLocal谈谈你的理解使用 ThreadLocal 需要注意些什么ThreadLocal 变量解决了多线程环境下单个线程中变量的共享问题使用名为ThreadLocalMap的哈希表进行维护key为ThreadLocal变量名value为ThreadLocal变量的值使用时需要注意以下几点线程之间的threadLocal变量是互不影响的使用private final static进行修饰防止多实例时内存的泄露问题线程池环境下使用后将threadLocal变量remove掉或设置成一个初始值83、为什么代码会重排序在执行程序时为了提供性能处理器和编译器常常会对指令进行重排序但是不能随意重排序不是你想怎么排序就怎么排序它需要满足以下两个条件在单线程环境下不能改变程序运行的结果存在数据依赖关系的不允许重排序需要注意的是重排序不会影响单线程环境的执行结果但是会破坏多线程的执行语义。84、什么是自旋很多 synchronized 里面的代码只是一些很简单的代码执行时间非常快此时等待的线程都加锁可能是一种不太值得的操作因为线程阻塞涉及到用户态和内核态切换的问题。既然 synchronized 里面的代码执行得非常快不妨让等待锁的线程不要被阻塞而是在 synchronized 的边界做忙循环这就是自旋。如果做了多次循环发现还没有获得锁再阻塞这样可能是一种更好的策略。85、多线程中 synchronized 锁升级的原理是什么synchronized 锁升级原理在锁对象的对象头里面有一个 threadid 字段在第一次访问的时候 threadid 为空jvm 让其持有偏向锁并将 threadid 设置为其线程 id再次进入的时候会先判断 threadid 是否与其线程 id 一致如果一致则可以直接使用此对象如果不一致则升级偏向锁为轻量级锁通过自旋循环一定次数来获取锁执行一定次数之后如果还没有正常获取到要使用的对象此时就会把锁从轻量级升级为重量级锁此过程就构成了 synchronized 锁的升级。锁的升级的目的锁升级是为了减低了锁带来的性能消耗。在 Java 6 之后优化 synchronized 的实现方式使用了偏向锁升级为轻量级锁再升级到重量级锁的方式从而减低了锁带来的性能消耗。86、synchronized 和 ReentrantLock 区别是什么synchronized 是和 if、else、for、while 一样的关键字ReentrantLock 是类这是二者的本质区别。既然 ReentrantLock 是类那么它就提供了比synchronized 更多更灵活的特性可以被继承、可以有方法、可以有各种各样的类变量synchronized 早期的实现比较低效对比 ReentrantLock大多数场景性能都相差较大但是在 Java 6 中对 synchronized 进行了非常多的改进。相同点两者都是可重入锁两者都是可重入锁。“可重入锁”概念是自己可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁此时这个对象锁还没有释放当其再次想要获取这个对象的锁的时候还是可以获取的如果不可锁重入的话就会造成死锁。同一个线程每次获取锁锁的计数器都自增1所以要等到锁的计数器下降为0时才能释放锁。主要区别如下ReentrantLock 使用起来比较灵活但是必须有释放锁的配合动作ReentrantLock 必须手动获取与释放锁而 synchronized 不需要手动释放和开启锁ReentrantLock 只适用于代码块锁而 synchronized 可以修饰类、方法、变量等。二者的锁机制其实也是不一样的。ReentrantLock 底层调用的是 Unsafe 的park 方法加锁synchronized 操作的应该是对象头中 mark wordJava中每一个对象都可以作为锁这是synchronized实现同步的基础普通同步方法锁是当前实例对象静态同步方法锁是当前类的class对象同步方法块锁是括号里面的对象87、Java Concurrency API 中的 Lock 接口(Lock interface)是什么对比同步它有什么优势Lock 接口比同步方法和同步块提供了更具扩展性的锁操作。他们允许更灵活的结构可以具有完全不同的性质并且可以支持多个相关类的条件对象。它的优势有1可以使锁更公平2可以使线程在等待锁的时候响应中断3可以让线程尝试获取锁并在无法获取锁的时候立即返回或者等待一段时间4可以在不同的范围以不同的顺序获取和释放锁整体上来说 Lock 是 synchronized 的扩展版Lock 提供了无条件的、可轮询的(tryLock 方法)、定时的(tryLock 带参方法)、可中断的(lockInterruptibly)、可多条件队列的(newCondition 方法)锁操作。另外 Lock 的实现类基本都支持非公平锁(默认)和公平锁synchronized 只支持非公平锁当然在大部分情况下非公平锁是高效的选择。88、jsp 和 servlet 有什么区别1servlet是服务器端的Java程序它担当客户端和服务端的中间层。2jsp全名为Java server pages中文名叫Java服务器页面其本质是一个简化的servlet设计。JSP是一种动态页面设计它的主要目的是将表示逻辑从servlet中分离出来。3JVM只能识别Java代码不能识别JSPJSP编译后变成了servletweb容器将JSP的代码编译成JVM能够识别的Java类servlet。4JSP有内置对象、servlet没有内置对象。89、jsp 有哪些内置对象作用分别是什么JSP九大内置对象pageContext页面上下文对象相当于页面中所有功能的集合通过它可以获取JSP页面的out、request、response、session、application对象。requestresponsesessionapplication应用程序对象application实现了用户间数据的共享可存放全局变量它开始于服务器启动知道服务器关闭。page就是JSP本身。exceptionoutout用于在web浏览器内输出信息并且管理应用服务器上的输出缓冲区作用域page。config取得服务器的配置信息。90、forward 和 redirect 的区别forward是直接请求转发redirect是间接请求转发又叫重定向。forward客户端和浏览器执行一次请求redirect客户端和浏览器执行两次请求。forward经典的MVC模式就是forwardredirect用于避免用户的非正常访问。例如用户非正常访问servlet就可以将HTTP请求重定向到登录页面。forward地址不变redirect地址改变。forward常用方法RequestDispatcher类的forward()方法redirect常用方法HttpServletRequest类的sendRedirect()方法。91、说一下 jsp 的 4 种作用域application、session、request、page92、session 和 cookie 有什么区别1存储位置不同cookie在客户端浏览器session在服务器2存储容量不同cookie4K一个站点最多保留20个cookiesession没有上线出于对服务器的保护session内不可存过多东西并且要设置session删除机制3存储方式不同cookie只能保存ASCII字符串并需要通过编码方式存储为Unicode字符或者二进制数据session中能存储任何类型的数据包括并不局限于String、integer、list、map等4隐私策略不同cookie对客户端是可见的不安全session存储在服务器上安全5有效期不同开发可以通过设置cookie的属性达到使cookie长期有效的效果session依赖于名为JESSIONID的cookie而cookie JSESSIONID的过期时间默认为-1只需关闭窗口该session就会失效因而session达不到长期有效的效果6跨域支持上不同cookie支持跨域session不支持跨域93、如果客户端禁止 cookie 能实现 session 还能用吗一般默认情况下在会话中服务器存储 session 的 sessionid 是通过 cookie 存到浏览器里。如果浏览器禁用了 cookie浏览器请求服务器无法携带 sessionid服务器无法识别请求中的用户身份session失效。但是可以通过其他方法在禁用 cookie 的情况下可以继续使用session。通过url重写把 sessionid 作为参数追加的原 url 中后续的浏览器与服务器交互中携带 sessionid 参数。服务器的返回数据中包含 sessionid浏览器发送请求时携带 sessionid 参数。通过 Http 协议其他 header 字段服务器每次返回时设置该 header 字段信息浏览器中 js 读取该 header 字段请求服务器时js设置携带该 header 字段。94、什么是上下文切换多线程编程中一般线程的个数都大于 CPU 核心的个数而一个 CPU 核心在任意时刻只能被一个线程使用为了让这些线程都能得到有效执行CPU 采取的策略是为每个线程分配时间片并轮转的形式。当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用这个过程就属于一次上下文切换。概括来说就是当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态以便下次再切换回这个任务时可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换。上下文切换通常是计算密集型的。也就是说它需要相当可观的处理器时间在每秒几十上百次的切换中每次切换都需要纳秒量级的时间。所以上下文切换对系统来说意味着消耗大量的 CPU 时间事实上可能是操作系统中时间消耗最大的操作。Linux 相比与其他操作系统包括其他类 Unix 系统有很多的优点其中有一项就是其上下文切换和模式切换的时间消耗非常少。95、cookie、session、token1、session机制session是服务端存储的一个对象主要用来存储所有访问过该服务端的客户端的用户信息也可以存储其他信息从而实现保持用户会话状态。但是服务器重启时内存会被销毁存储的用户信息也就消失了。不同的用户访问服务端的时候会在session对象中存储键值对“键”用来存储开启这个用户信息的“钥匙”在登录成功后“钥匙”通过cookie返回给客户端客户端存储为sessionId记录在cookie中。当客户端再次访问时会默认携带cookie中的sessionId来实现会话机制。1session是基于cookie的。cookie的数据4k左右cookie存储数据的格式字符串keyvaluecookie存储有效期可以自行通过expires进行具体的日期设置如果没设置默认是关闭浏览器时失效。cookie有效范围当前域名下有效。所以session这种会话存储方式方式只适用于客户端代码和服务端代码运行在同一台服务器上前后端项目协议、域名、端口号都一致即在一个项目下2session持久化用于解决重启服务器后session消失的问题。在数据库中存储session而不是存储在内存中。通过包express-mysql-session。当客户端存储的cookie失效后服务端的session不会立即销毁会有一个延时服务端会定期清理无效session不会造成无效数据占用存储空间的问题。2、token机制适用于前后端分离的项目前后端代码运行在不同的服务器下请求登录时token和sessionid原理相同是对key和key对应的用户信息进行加密后的加密字符登录成功后会在响应主体中将{token“字符串”}返回给客户端。客户端通过cookie都可以进行存储。再次请求时不会默认携带需要在请求拦截器位置给请求头中添加认证字段Authorization携带token信息服务器就可以通过token信息查找用户登录状态。96、说一下 session 的工作原理当客户端登录完成后会在服务端产生一个session此时服务端会将sessionid返回给客户端浏览器。客户端将sessionid储存在浏览器的cookie中当用户再次登录时会获得对应的sessionid然后将sessionid发送到服务端请求登录服务端在内存中找到对应的sessionid完成登录如果找不到返回登录页面。97、http 响应码 301 和 302 代表的是什么有什么区别301和302状态码都表示重定向当浏览器拿到服务器返回的这个状态码后悔自动跳转到一个新的URL地址。301代表永久性重定向旧地址被永久移除客户端向新地址发送请求。302代表暂时性重定向旧地址还在客户端继续向旧地址发送请求。303代表暂时性重定向重定向到新地址时必须使用GET方法请求新地址。307代表暂时性重定向与302的区别在于307不允许从POST改为GET。307代表永久性重定向与301的区别在于308不允许从POST改为GET。98、简述 tcp 和 udp的区别TCP是传输控制协议UDP是用户数据表协议TCP长连接UDP无连接UDP程序结构较简单只需发送无须接收TCP可靠保证数据正确性、顺序性UDP不可靠可能丢数据TCP适用于少量数据UDP适用于大量数据传输TCP速度慢UDP速度快99、tcp 为什么要三次握手两次不行吗为什么因为客户端和服务端都要确认连接①客户端请求连接服务端②针对客户端的请求确认应答并请求建立连接③针对服务端的请求确认应答建立连接两次无法确保A能收到B的数据100、OSI 的七层模型都有哪些101、get 和 post 请求有哪些区别get请求参数是连接在url后面的,而post请求参数是存放在requestbody内的get请求因为浏览器对url长度有限制所以参数个数有限制而post请求参数个数没有限制因为get请求参数暴露在url上,所以安全方面post比get更加安全get请求只能进行url编码,而post请求可以支持多种编码方式get请求参数会保存在浏览器历史记录内,post请求并不会get请求浏览器会主动cache,post并不会,除非主动设置get请求产生1个tcp数据包,post请求产生2个tcp数据包在浏览器进行回退操作时,get请求是无害的,而post请求则会重新请求一次浏览器在发送get请求时会将header和data一起发送给服务器,服务器返回200状态码,而在发送post请求时,会先将header发送给服务器,服务器返回100,之后再将data发送给服务器,服务器返回200 OK102、什么是 XSS 攻击如何避免xss(Cross Site Scripting)即跨站脚本攻击是一种常见于web应用程序中的计算机安全漏洞。指的是在用户浏览器上在渲染DOM树的时候执行了不可预期的JS脚本从而发生了安全问题。XSS就是通过在用户端注入恶意的可运行脚本若服务端对用户的输入不进行处理直接将用户的输入输出到浏览器然后浏览器将会执行用户注入的脚本。 所以XSS攻击的核心就是浏览器渲染DOM的时候将文本信息解析成JS脚本从而引发JS脚本注入那么XSS攻击的防御手段就是基于浏览器渲染这一步去做防御。只要我们使用HTML编码将浏览器需要渲染的信息编码后浏览器在渲染DOM元素的时候会自动解码需要渲染的信息将上述信息解析成字符串而不是JS脚本这就是我们防御XSS攻击的核心想法。预防1、获取用户的输入不用innerHtml,用innerText.2、对用户的输入进行过滤如对 /等进行转义103、什么是 CSRF 攻击如何避免跨站请求伪造英语Cross-site request forgery也被称为 one-click attack 或者 session riding通常缩写为 CSRF 或者 XSRF 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。跟跨网站脚本XSS相比XSS 利用的是用户对指定网站的信任CSRF 利用的是网站对用户网页浏览器的信任。1、攻击细节跨站请求攻击简单地说是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作如发邮件发消息甚至财产操作如转账和购买商品。由于浏览器曾经认证过所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞简单的身份验证只能保证请求发自某个用户的浏览器却不能保证请求本身是用户自愿发出的。例子假如一家银行用以运行转账操作的URL地址如下http://www.examplebank.com/withdraw?accountAccoutNameamount1000forPayeeName那么一个恶意攻击者可以在另一个网站上放置如下代码 img srchttp://www.examplebank.com/withdraw?accountAliceamount1000forBadman如果有账户名为Alice的用户访问了恶意站点而她之前刚访问过银行不久登录信息尚未过期那么她就会损失1000资金。这种恶意的网址可以有很多种形式藏身于网页中的许多地方。此外攻击者也不需要控制放置恶意网址的网站。例如他可以将这种地址藏在论坛博客等任何用户生成信息的网站中。这意味着如果服务端没有合适的防御措施的话用户即使访问熟悉的可信网站也有受攻击的危险。透过例子能够看出攻击者并不能通过CSRF攻击来直接获取用户的账户控制权也不能直接窃取用户的任何信息。他们能做到的是欺骗用户浏览器让其以用户的名义运行操作。2、防御措施检查Referer字段HTTP头中有一个Referer字段这个字段用以标明请求来源于哪个地址。在处理敏感数据请求时通常来说Referer字段应和请求的地址位于同一域名下。以上文银行操作为例Referer字段地址通常应该是转账按钮所在的网页地址应该也位于http://www.examplebank.com之下。而如果是CSRF攻击传来的请求Referer字段会是包含恶意网址的地址不会位于http://www.examplebank.com之下这时候服务器就能识别出恶意的访问。这种办法简单易行工作量低仅需要在关键访问处增加一步校验。但这种办法也有其局限性因其完全依赖浏览器发送正确的Referer字段。虽然http协议对此字段的内容有明确的规定但并无法保证来访的浏览器的具体实现亦无法保证浏览器没有安全漏洞影响到此字段。并且也存在攻击者攻击某些浏览器篡改其Referer字段的可能。3、添加校验token由于CSRF的本质在于攻击者欺骗用户去访问自己设置的地址所以如果要求在访问敏感数据请求时要求用户浏览器提供不保存在cookie中并且攻击者无法伪造的数据作为校验那么攻击者就无法再运行CSRF攻击。这种数据通常是窗体中的一个数据项。服务器将其生成并附加在窗体中其内容是一个伪随机数。当客户端通过窗体提交请求时这个伪随机数也一并提交上去以供校验。正常的访问时客户端浏览器能够正确得到并传回这个伪随机数而通过CSRF传来的欺骗性攻击中攻击者无从事先得知这个伪随机数的值服务端就会因为校验token的值为空或者错误拒绝这个可疑请求。104、如何实现跨域说一下 JSONP 实现原理cors是目前主流的跨域解决方案跨域资源共享(CORS) 是一种机制它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时资源会发起一个跨域 HTTP 请求。最方便的跨域方案Nginxnginx是一款极其强大的web服务器其优点就是轻量级、启动快、高并发。现在的新项目中nginx几乎是首选我们用node或者java开发的服务通常都需要经过nginx的反向代理。反向代理的原理很简单即所有客户端的请求都必须先经过nginx的处理nginx作为代理服务器再讲请求转发给node或者java服务这样就规避了同源策略。105、websocket应用的是哪个协议WebSocket是一个允许Web应用程序(通常指浏览器)与服务器进行双向通信的协议。HTML5的WebSocket API主要是为浏览器端提供了一个基于TCP协议实现全双工通信的方法。WebSocket优势 浏览器和服务器只需要要做一个握手的动作在建立连接之后双方可以在任意时刻相互推送信息。同时服务器与客户端之间交换的头信息很小。106、说一下 tcp 粘包是怎么产生的发送方需要等缓冲区满才能发送出去造成粘包接收方不及时接收缓冲区的包造成粘包108、什么是设计模式你是否在你的代码里面使用过任何设计模式1、什么是设计模式设计模式是解决软件开发某些特定问题而提出的一些解决方案也可以理解为解决问题的一些固定思路。通过设计模式可以帮助我们增强代码的可复用性、可扩展性、灵活性。我们使用设计模式的最终目的是实现代码的高内聚、低耦合。2、设计模式的七大原则单一职责原则接口隔离原则依赖倒转原则里式替换原则开闭原则迪米特法则合成复用原则3、你是否在你的代码里面使用过任何设计模式1单例模式JDK种的runtimeSpring种的singeton。2简单工厂模式Spring的BeanFactory根据传入一个唯一标识来获得bean对象。3原型模式clone()4代理模式Spring的AOP中Spring实现AOP功能的原理就是代理模式①JDK动态代理。②CGLIB动态代理使用Advice通知对类进行方法级别的切面增强。5装饰器模式为类添加新的功能防止类爆炸IO流、数据源包装Spring中用到的装饰器模式表现在Wrapper。109、Java 中什么叫单例设计模式请用 Java 写出线程安全的单例模式保证程序只有一个对象的实例叫做单例模式内部类的方式实现单例模式是线程安全的双重验证方式实现单例模式也是线程安全的110、在 Java 中什么叫观察者设计模式observer design pattern1、观察者模式是一种一对多的依赖关系让多个观察者同时监听某一主题对象。当这个主题对象发生变化时会通知所有观察者对象使它们能够自动更新自己。2、JAVA提供的对观察者模式的支持在JAVA语言的java.util库里面提供了一个Observable类以及一个Observer接口构成JAVA语言对观察者模式的支持。1Observer接口这个接口只定义了一个方法即update()方法当被观察者对象的状态发生变化时被观察者对象的notifyObservers()方法就会调用这一方法。public interface Observer { void update(Observable o, Object arg); }2Observable类被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象这些方法中有两个对Observable的子类非常重要一个是setChanged()另一个是notifyObservers()。第一方法setChanged()被调用之后会设置一个内部标记变量代表被观察者对象的状态发生了变化。第二个是notifyObservers()这个方法被调用时会调用所有登记过的观察者对象的update()方法使这些观察者对象可以更新自己。111、使用工厂模式最主要的好处是什么在哪里使用1、工厂模式好处良好的封装性、代码结构清晰扩展性好如果想增加一个产品只需扩展一个工厂类即可典型的解耦框架2、在哪里使用需要生成对象的地方不同数据库的访问112、请解释自动装配模式的区别有五种自动装配的方式可以用来指导 Spring 容器用自动装配方式来进行依赖注入。1、no默认的方式是不进行自动装配通过显式设置 ref 属性来进行装配。第 402 页 共 485 页2、byName通过参数名 自动装配Spring 容器在配置文件中发现 bean的 autowire 属性被设置成 byname之后容器试图匹配、装配和该 bean 的属性具有相同名字的 bean。3、byType:通过参数类型自动装配Spring 容器在配置文件中发现 bean的 autowire 属性被设置成 byType之后容器试图匹配、装配和该 bean 的属性具有相同类型的 bean。如果有多个 bean 符合条件则抛出错误。4、constructor这个方式类似于 byType 但是要提供给构造器参数如果没有确定的带参数的构造器参数类型将会抛出异常。5、autodetect首先尝试使用 constructor 来自动装配如果无法工作则使用 byType 方式。篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题需要完整版的小伙伴可以点击下方名片获取
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

营销型网站建设信融上海网站建设费用多少

外卖订单自动化采集系统构建指南 【免费下载链接】waimai-crawler 外卖爬虫,定时自动抓取三大外卖平台上商家订单,平台目前包括:美团,饿了么,百度外卖 项目地址: https://gitcode.com/gh_mirrors/wa/waimai-crawler …

张小明 2025/12/25 20:47:42 网站建设

做网站开发需要学那些东西wordpress 屏蔽搜索引擎

深入了解Samba配置与Linux安全框架 一、Samba配置与使用 Samba是一个能让Linux系统与Windows系统实现文件和打印机共享的工具。下面详细介绍其配置和使用步骤。 1. Samba配置 - 配置Samba时,需选择局域网中现有的Windows工作组名称,点击“Next”,接着可选择服务器类型…

张小明 2025/12/29 17:25:00 网站建设

Wordpress 免登录付费查看台州seo网站建设费用

LangFlow构建可疑行为模式识别系统 在企业安全防护日益复杂的今天,传统基于规则的入侵检测系统(IDS)正面临严峻挑战:攻击手段不断演化,异常行为越来越隐蔽,而人工编写和维护检测逻辑的成本却居高不下。尤其…

张小明 2025/12/26 6:02:47 网站建设

啊宝贝才几天没做网站网站不换域名换空间

AJAX并不是一种独立的请求方法,而是一种「前端异步请求数据、实现页面局部刷新」的技术思想/方案,我们先厘清核心概念,再详细说明AJAX的实现方式、历史演变及具体用法: 一、先明确:AJAX的本质与核心概念 1. AJAX的全…

张小明 2025/12/26 6:02:46 网站建设

申请的网站怎么建设山东网站建设团队

本周工作内容:1.12.8,搜集好照片,在数据库上完成好照片的部署。完成情况100%/工作饱和度52.12.10,下载测试工具,准备测试文档。完成情况100%/工作饱和度53.12.12,完成周报,完成情况100%/工作饱和…

张小明 2025/12/26 6:02:44 网站建设

北京响应式网站建设站群网站内容

Linly-Talker:让历史人物“开口说话”的AI数字人技术实践 在博物馆的展柜前,一位学生凝视着爱因斯坦的老照片,轻声问道:“您当年是怎么想到相对论的?”话音刚落,照片中的科学家忽然眨了眨眼,嘴角…

张小明 2025/12/26 6:02:47 网站建设