请你说说线程和协程的区别
得分点 地址空间、开销、并发性、内存 标准回答 进程和线程的主要差别在于它们是不同的操作系统资源管理方式。
- 进程有独立的地址空间, 线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间
- 进程和线程切换时,需要切换进程和线程的上下文,进程的上下文切换时间开销远远大于线程上下文切换时间,耗费资源较大,效率要差一些
- 进程的并发性较低,线程的并发性较高
- 每个独立的进程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
- 系统在运行的时候会为每个进程分配不同的内存空间,而对线程而言,除了 CPU 外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源
- 一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
HashMap 的数据结构,和 HashTable 的区别
HashMap不是线程安全的,HashTable是线程安全。
HashMap允许空(null)的键和值(key),HashTable则不允许。
HashMap性能优于Hashtable。
HashMap如何实现线程安全
分段锁和CAS
HashMap的扩容机制
HashMap的扩展原理是HashMap用一个新的数组替换原来的数组
启动线程的方式,常用的方式
第一种:new Thread().start();
第二种:new Thread(Runnable).start();
第三种:通过线程池可以启动一个新的线程,其实线程池也是用的两种方式之一,Executors.newCachedThreadPool()或者FutureTask+Callable
yield() 和 join()
yield()方法:是暂停当前正在执行的线程对象,并执行其他线程。
jion()方法:线程实例的join()方法可以使得一个线程在另一个线程结束后再执行,即也就是说使得当前线程可以阻塞其他线程执行。
线程中断的方式
- stop() 强制线程,可能导致线程中的资源没有释放,比如在try-catch-finally中释放资源,直接中断,不会调用finally块。
- new Thread().interrupte()
协作式的中断线程,不会强制中断线程,会发一个interrupt的信号,线程run方法中,如果有Thread.sleep()或者wait,捕获了InterruptedException,会命中该catch, 重置interrupt标记位,如果需要处理该标记位,需要显示调用interrupt(),再判断isInterrupted(),判断run方法执行结束(如:在while循环中,break )。 - new Thread().isInterrupted()
线程是否中断的标记位 - Thread.interrupted()
静态方法,获取当前线程的中断标记位。调用之后,会重置interrupt标记位,再次通过isInterrupted()获取就为false啦
负载均衡算法
负载均衡算法有:轮询法、加权轮询法、加权随机法、最小连接数法、随机法、源地址哈希法
七层协议
应用层(Application)、表示层(Presentation)、会话层(Session)、传输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)
TCP 的三次握手,四次握手
数据库索引
主键索引(PRIMAY KEY)
唯一索引(UNIQUE)
常规索引(INDEX)
全文索引(FULLTEXT)
作用:
快速定位特定数据
注意:
只能用于MyISAM类型的数据表
只能用于CHAR ,VARCHAR,TEXT数据列类型
使用大型数据集
B+ 树的优势
- 它是 B Tree 的变种,B Tree 能解决的问题,它都能解决。B Tree 解决的两大问题是(每个节点存储更多关键字,路数更多)
- 扫库、扫表能力更强(如果我们要对表进行全表扫描,只需要遍历叶子节点就可以了,不需要遍历整棵 B+Tree 拿到所有的数据)
- B+Tree 的磁盘读写能力相对于 B Tree 来说更强,同数据量下磁盘I/0次数更少(根节点和枝节点不保存数据区,所以一个节点可以保存更多的关键字,一次磁盘加载的关键字更多)
- 范围查询和排序能力更强(因为叶子节点上有下一个数据区的指针,数据形成了链表)
- 效率更加稳定(B+Tree 永远是在叶子节点拿到数据,所以 IO 次数是稳定的)
索引优化
索引失效
- MySQL 可以为多个字段创建索引,一个索引可以包括 16 个字段。对于多列索引,过滤条件要使用索引,必须按照索引建立的顺序,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用。如果查询条件中没有使用这些字段中第 1 个字段时,多列(或联合)索引不会被使用。
- 计算、函数、类型转换(自动或手动)导致索引失效
- 范围条件右边的列索引失效
应用开发中范围查询,例如:金额查询,日期查询往往都是范围查询。应将查询条件放置 WHERE 语句最后。(创建的联合索引中,务必把范围涉及到的字段写在最后) - 不等于( != 或者 <> )索引失效
- is null 可以使用索引,is not null 无法使用索引
最好在设计数据表的时候就将字段设置为 NOT NULL 约束,比如可以将 INT 类型的字段,默认值设置为 0。将字符类型的默认值设置为空字符串 '' 。同理,在查询中使用 not like 也无法使用索引,导致全表扫描 - like 以通配符 % 开头索引失效
- OR 前后存在非索引的列,索引失效
- 数据表和表的字符集统一使用 utf8mb4
统一使用 utf8mb4 兼容性更好,统一字符集可以避免由于字符集转换产生的乱码。不同的字符集进行比较前需要进行转换会造成索引失效
SQL 的执行过程
1、首先客户端发送请求到服务端,建立连接。
2、服务端先看下查询缓存,对于更新某张表的SQL,该表的所有查询缓存都失效。
3、接着来到解析器,进行语法分析,一些系统关键字校验,校验语法是否合规。
4、然后优化器进行SQL优化,比如怎么选择索引之类,然后生成执行计划。
5、执行引擎去存储引擎查询需要更新的数据。
6、存储引擎判断当前缓冲池中是否存在需要更新的数据,存在就直接返回,否则去从磁盘加载数据。
7、执行引擎调用存储引擎API去更新数据。
8、存储引擎更新数据,同时写入undo_log、redo_log信息。
9、执行引擎写binlog,提交事务,流程结束。
这个 SQL 语句加了哪些锁?
这篇文章就来详细总结下 InnoDB 存储引擎中的行锁的加锁规则,并辅以实例解释。
首先众所周知,InnoDB 三种行锁:
- Record Lock(记录锁):锁住某一行记录
- Gap Lock(间隙锁):锁住一段左开右开的区间
- Next-key Lock(临键锁):锁住一段左开右闭的区间
死锁的条件
1、互斥条件:一个资源每次只能被一个进程使用
2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
3、不剥夺条件: 进程已获得的资源,在末使用完之前,不能强行剥夺
4、循环等待条件: 若干进程之间形成一种头尾相接的循环等待资源关系
如果一个事务里面的几个SQL都是异步执行的,那么这些SQL还是属于原来的事务吗
@Async使用与@transactional类似
注意:如下方式会使@Async失效
- 一、异步方法使用static修饰
- 二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
- 三、异步方法不能与异步方法在同一个类中
- 四、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
- 五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
- 六、在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效。
- 七、调用被@Async标记的方法的调用者不能和被调用的方法在同一类中不然不会起作用!!!!!!!
- 八、使用@Async时要求是不能有返回值的不然会报错的因为异步要求是不关心结果的
分布式Springcloud+Dubbo知识(Eurake+Ribbon+Fein+GateWay等)
Mysql调优
索引调优
SQL 性能优化 explain 中的 type:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好
Redis 数据类型
redis的五种数据类型为:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)。
1、string(字符串)是redis最常用的类型,可以包含任何数据,一个key对应一个value,在Rediss中是二进制安全的。
2、hash(哈希)是一个string 类型的field和value的映射表,适合被用于存储对象。
3、list(列表)是一个链表结构,按照插入顺序排序。
4、set(集合)是 string 类型的无序集合。
5、zset(有序集合)是string类型元素的集合,zset是插入有序的,即自动排序。
Linux命令
Autowired和Resource注解的区别?
1、@Autowired注解由Spring提供,只按照byType注入;@resource注解由J2EE提供,默认按照byName自动注入。
2、@Autowired默认按类型进行装配,@Resource默认按照名称进行装配。
Spring的IOC是怎么实现的
工厂 + 反射
jdk动态代理和cglib动态代理的区别
1、Jdk动态代理:利用拦截器(必须实现InvocationHandler接口)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
2、 Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来进行代理
如果想要实现JDK动态代理那么代理类必须实现接口,否则不能使用;
如果想要使用CGlib动态代理,那么代理类不能使用final修饰类和方法;
用了GateWay网关之后为什么跨域问题就不存在了
既然是在网关里边来解决跨域问题的,就不能在下流的服务里边再重复引入解决跨域的配置了。否则会导致跨域失效,报跨域的问题。
Java的类加载机制,我说的是双亲委派模型
如何设计权限管理模块
用户权限表的设计
nginx的使用
dubbo和springcloud的区别,以及dubbo的功能和SpringCloud组件的对应
熔断和降级
SpringBoot自动装配
聚簇索引和非聚簇索引
在聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找。辅助索引叶子节点存储的不再是行的物理位置,而是主键值。通过辅助索引首先找到的是主键值,再通过主键值找到数据行的数据页,再通过数据页中的Page Directory找到数据。
mysql查询重复字段
面向对象特性
多态
抽象类和接口(1.8新特性)
有哪些设计模式?
单例模式属于面向对象三大特性中的哪一种
OOM
GC
有哪些类加载器,怎么加载类
- 启动类加载器(Bootstrap ClassLoader) 用来加载java核心类库,无法被java程序直接引用。
- 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供 一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
- 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。
- 用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。
哪些集合是线程安全的
Vector、HashTable、Stack、ArrayBlockingQueue、ConcurrentHashMap、ConcurrentLinkedQueue等
线程间的通信方式
- 通过 volatile 关键字
- 通过 Object类的wait/notify方法
- 通过 condition的await/signal 方法
- 通过 join 的方式
- 通过 CountDownLunch
HTTPS有哪些方法实现安全
内容加密 建立一个信息安全通道,来保证数据传输的安全;
身份认证 通讯双方进行身份认证, 确认网站的真实性
数据完整性 防止内容被第三方冒充或者篡改
Redis缓存雪崩击穿
雪崩、击穿、穿透强引用、软引用、弱引用和虚引用的区别
1、强引用(StrongReference)
最普遍的一种引用方式,如String s = “abc”,变量s就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。
2、软引用(SoftReference)
用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。
3、弱引用(WeakReference)
弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。
4、虚引用(PhantomReference)
就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。
虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
Happens Before规则,设计思想是什么
happens-before 关系是用来描述两个操作的内存可见性的。如果操作 X happens-before 操作 Y,那么 X 的结果对于 Y 可见。Java 内存模型底层是通过内存屏障(memory barrier)来禁止重排序的。
谈谈fail-fast与fail-safe是什么以及工作机制
fail-fast
快速失败,例如在arrayList中使用迭代器遍历时,有另外的线程对arrayList的存储数组进行了改变,比如add、delete、等使之发生了结构上的改变,
所以Iterator就会快速报一个java.util.ConcurrentModificationException 异常(并发修改异常),这就是快速失败。
fail-safe
安全失败,在java.util.concurrent下的类,都是线程安全的类,他们在迭代的过程中,如果有线程进行结构的改变,不会报异常,而是正常遍历,这就是安全失败
但java.util.concurrent包下,对集合有结构的改变,却不会报异常?
在concurrent下的集合类增加元素的时候使用Arrays.copyOf()来拷贝副本,在副本上增加元素,如果有其他线程在此改变了集合的结构,那也是在副本上的改变,而不是影响到原集合;
迭代器还是照常遍历,遍历完之后,改变原引用指向副本,所以总的一句话就是如果在次包下的类进行增加删除,就会出现一个副本。所以能防止fail-fast,这种机制并不会出错,所以我们叫这种现象为fail-safe。
总结
fail-fast是否会发生,与线程安全与否,没有关系,与实现增删的底层机制有关;
是直接操作引用,还是操作副本
单点登录实现
mycat实现
HttpClient连接池
Synchronized
线程池核心参数
设计模式
项目的jvm调优
服务器配置
进程线程的区别
进程的通信方式
线程的通信方式
leecode19 删除倒数第n个节点
异常的分类
springboot自定义starter
springboot多环境配置
sql注入
http状态码
401 (Unauthorized/未授权) 403 (SC_FORBIDDEN)的意思是除非拥有授权否则服务器拒绝提供所请求的资源。这个状态经常会由于服务器的损坏文件或目录许可而引起。
AOP概念及应用场景
反射应用场景
远程访问mysql访问不到可能是什么问题
io阻塞和非阻塞的区别
MySQL 的基本数据类型
MySQL 的索引
MySQL 的事务,事务失效的场景
SQL 优化的思路
场景:每天上百万的数据插入一个表,如何处理
Redis 的基本数据类型
Redis 的持久化方式
Redis 主从复制原理
TCP 和 UDP
粘包和拆包的原因,解决方法
Netty 的核心组成
Spring AOP 的原理,通知类型
MyBatis ,# 和 $ 的区别,二级缓存
{} 是预编译处理,像传进来的数据会加个" "(#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号)方式一般用于传入数据库对象,例如传入表名。
使用 {value}。value 应该是一个数值吧。然后如果对方传过来的是 001 and name = tom。这样不就相当于多加了一个条件嘛?把SQL语句直接写进来了。如果是攻击性的语句呢?001;drop table user,直接把表给删了。
所以为了防止 SQL 注入,能用 #{} 的不要去用 ${}
如果非要用 ${} 的话,那要注意防止 SQL 注入问题,可以手动判定传入的变量,进行过滤,一般 SQL 注入会输入很长的一条 SQL 语句
数据库隔离级别
1.读未提交(Read uncommitted):这种事务隔离级别下,select语句不加锁。
此时,可能读取到不一致的数据,即“读脏 ”。这是并发最高,一致性最差的隔离级别。
2.读已提交(Read committed):可避免脏读的发生。
3.可重复读(Repeatable read):MySql默认隔离级别。可避免脏读 、不可重复读的发生。
4.串行化(Serializable ):可避免 脏读、不可重复读、幻读 的发生。
以上四种隔离级别最高的是串行化级别,最低的是读未提交级别,当然级别越高,执行效率就越低。像串行化这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为可重复读。
在MySQL数据库中,支持上面四种隔离级别,默认为可重复读;而在 Oracle数据库 中,只支持串行化级别和读已提交,其中默认的为读已提交级别。
(1).脏读:
脏读是指一个事务在处理数据的过程中,读取到另一个未提交事务的数据。
(2).不可重复读:
不可重复读是指对于数据库中的某个数据,一个事务范围内的多次查询却返回了不同的结果,这是由于在查询过程中,数据被另外一个事务修改并提交了。
(3).幻读
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
解决不可重复读的方法是锁行,解决幻读的方式是锁表。
常见的设计模式,抽象模板设计模式
消息队列的应用场景
写个观察者模式的简单demo
你的项目有用到事务吗
final和finally
sleep和wait区别,什么时候用
HashMap put流程,扩容机制
深拷贝浅拷贝
四种引用
http请求结构,常用状态码,206什么时候用,304什么时候用,http缓存是什么
常用http请求
线程池参数,原理
垃圾回收机制
秒杀如何实现
如何解决超发问题
redis用了哪些命令
AOP原理,几个切入点
MySQL的引擎和回表问题
JVM调优有用过哪些工具
类加载器
SpringCloud的熔断机制
JVM是干什么的
ArrayList的底层实现原理,为什么底层用数组
你认为该怎么解决秒杀问题
RabbitMQ怎么做到的能够处理高并发
voliate的使用,和synchronized的区别
voliate的底层实现
sychronized的底层实现
对http的了解说一说http的状态码以及你项目中有没有使用这些状态码,如何使用的
项目中使用的http的请求方式有哪些,怎么使用的
springboot的事务管理用过吗(没有)
你认为一个事务应该怎么设计?(不太懂,简单瞎说了点)
有个订单表,有两个字段,一个是用户id,一个是生成时间。有个业务是用户需要查询自己的订单,并以分页展示,那这个表的索引该怎么建立?项目的索引是怎么设计的?
算法
合并两个排序数组
实现 LRU 缓存:最长时间未使用的元素将从缓存中逐出
因此,LRU缓存只是 DoublyLinkedList
和 HashMap
的组合,如下所示:
这样做的目的是将密钥保留在Map上,以便快速访问队列中的数据。
如果密钥存在于 HashMap 中,则为缓存命中,否则,就是缓存丢失了。
在缓存命中后,我们将执行两个步骤:
- 删除hit元素并将其添加到列表前面。
- 使用列表前面的新引用更新HashMap 。
缓存未命中后,我们将执行两个步骤:
- 在列表前面添加新元素。
- 在HashMap中添加一个新条目并引用列表的标题。
说一说虚拟地址空间有哪些部分
说一说ArrayList的实现原理
说一说NIO的实现原理
Java的基本数据类型有哪些
java中共有8种基本类型,可分为三类:
数值类型:byte,short,int,long,float,double
布尔类型:boolean
字符类型:char
java为其提供了8种对应的包装类:Byte、Short、Integer、Long、Float、Double、Boolean、Character
Java语言是面向对象的编程语言,而基本数据类型声明的变量并不是对象,为其提供包装类,增强了Java面向对象的性质。
而且,如果只有基本数据类型,使用时是很不方便的,比如,在集合类中,无法将int 、double等类型放进去的,因为集合的容器要求元素是Object类型。
此外,包装类还为基本类型添加了属性和方法,丰富了基本类型的操作。如当我们想知道int取值范围的最小值,我们需要通过运算,如下面所示,但是有了包装类,我们可以直接使用Integer.MAX_VALUE即可。
Spring中IOC的理解
谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
Mysql的存储引擎有哪些。表的设计有哪些原则,sql的语句优化怎么处理。联合索引什么时候使用
1)MyISAM、InnoDB、MEMORY(内存)、ARCHIVE(独立、压缩 插入性能好,不支持索引)
2)数据库设计三范式
- 第一范式(确保每列保持原子性)
- 第二范式(确保表中的每列都和主键相关)
- 第三范式(确保每列都和主键列直接相关,而不是间接相关)
3)SQL语句层面优化
- 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上合理建立索引。
- 防止产生索引失效
- 建议能用int、char就用 节约空间
4)联合索引一般在where的条件有多个时,如果没有联合索引,就只能依据有索引条件的结果再查找出最终结果
MySQL的体系结构
MySQL整体的逻辑结构可以分为4层, 客户层、服务层、存储引擎层、数据层
客户层: 进行相关的连接处理、权限控制、安全处理等操作
服务层: 负责与客户层进行连接处理、处理以及执行SQL语句等,主要包含连接器、查询缓存、优化器、执行器、存储引擎,触发器、视图等也在这一层
存储引擎层: 存储引擎层负责对数据的存储和提取,常见的存储引擎有InnoDB、MyISAM、Memory等,在MySQL5.5之后,MySQL默认的存储引擎就是InnoDB,InnoDB默认使用的索引结构就是B+树,上面的服务层就是通过API接口与存储引擎层进行交互的
数据层: 是主要包括MySQL中存储数据的底层文件,与上层的存储引擎进行交互,是文件的物理存储层。其存储的文件主要有:日志文件、数据文件、配置文件、MySQL的进行pid文件和Socket文件等
5)联合索引的失效条件
对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部分,但只能是最左侧部分。例如索引是key index (a,b,c)。可以支持a | a,b| a,b,c 3种组合进行查找,但不支持 b,c进行查找 。当最左侧字段是常量引用时,索引就十分有效。
谈谈这几个常见的多线程面试题
有三种方式可以用来创建线程:
- 继承Thread类
- 实现Runnable接口
- 应用程序可以使用Executor框架来创建线程池
概括的解释下线程的几种可用状态
-
新建( new ):新创建了一个线程对象
-
可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象的 start ()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取CPU的使用权
-
运行( running ):可运行状态( runnable )的线程获得了CPU时间片( timeslice ) ,执行程序代码
-
阻塞( block ):阻塞状态是指线程因为某种原因放弃了CPU 使用权,也即让出了 CPU timeslice ,暂时停止运行。直到线程进入可运行( runnable )状态,才有 机会再次获得 cpu timeslice 转到运行( running )状态。
阻塞的情况分三种:
- 等待阻塞:运行( running )的线程执行 o . wait ()方法, JVM 会把该线程放 入等待队列( waitting queue )中。
- 同步阻塞:运行( running )的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池( lock pool )中。
- 其他阻塞: 运行( running )的线程执行 Thread . sleep ( long ms )或 t . join ()方法,或者发出了 I / O 请求时, JVM 会把该线程置为阻塞状态。当 sleep ()状态超时、 join ()等待线程终止或者超时、或者 I / O 处理完毕时,线程重新转入可运行( runnable )状态。
- 死亡( dead ):线程 run ()、 main () 方法执行结束,或者因异常退出了 run ()方法,则该线程结束生命周期。死亡的线程不可再次复生。
Java序列化与反序列化三连问:是什么?为什么要?如何做?
Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程:
序列化:对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。核心作用是对象状态的保存与重建。
反序列化:客户端从文件中或网络上获得序列化后的对象字节流,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。
一:对象序列化可以实现分布式对象。
二:java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。
三:序列化可以将内存中的类写入文件或数据库中。
四:对象、文件、数据,有许多不同的格式,很难统一传输和保存。
序列化以后就都是字节流了,无论原来是什么东西,都能变成一样的东西,就可以进行通用的格式传输或保存,传输结束以后,要再次使用,就进行反序列化还原,这样对象还是对象,文件还是文件。
为什么Java线程没有Running状态
与传统的running状态的区别
有人常觉得 Java 线程状态中还少了个 running 状态,这其实是把两个不同层面的状态混淆了。对 Java 线程状态而言,不存在所谓的running 状态,它的 runnable 状态包含了 running 状态。
你能说说Java中Comparable和Comparator的区别吗
如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法。
实现Comparable接口的方式比实现Comparator接口的耦合性要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修改。
请你谈谈关于IO同步、异步、阻塞、非阻塞的区别
blocking 和 non-blocking的区别在哪,synchronous IO和asynchronous IO的区别在哪。
A用的是最老式的鱼竿,所以呢,得一直守着,等到鱼上钩了再拉杆
B的鱼竿有个功能,能够显示是否有鱼上钩,所以呢,B就和旁边的MM聊天,隔会再看看有没有鱼上钩,有的话就迅速拉杆
C用的鱼竿和B差不多,但他想了一个好办法,就是同时放好几根鱼竿,然后守在旁边,一旦有显示说鱼上钩了,它就将对应的鱼竿拉起来
D是个有钱人,干脆雇了一个人帮他钓鱼,一旦那个人把鱼钓上来了,就给D发个短信。
如何判断一个对象是否存活
该类的所有实例都已经被回收
加载该类的ClassLoader已经被回收
该类对应的java.lang.Class对象已经没有任何地方被引用,无法在任何地方通过反射访问该类的方法。
说一下线程池内部工作原理
先看一下ThreadPoolExecutor参数最全的构造方法:
构造方法- corePoolSize:线程池的核心线程数,说白了就是,即便是线程池里没有任何任务,也会有corePoolSize个线程在候着等任务。
- maximumPoolSize:最大线程数,不管你提交多少任务,线程池里最多工作线程数就是maximumPoolSize。
- keepAliveTime:线程的存活时间。当线程池里的线程数大于corePoolSize时,如果等了keepAliveTime时长还没有任务可执行,则线程退出。
- unit:这个用来指定keepAliveTime的单位,比如秒:TimeUnit.SECONDS。
- workQueue:一个阻塞队列,提交的任务将会被放到这个队列里。
- threadFactory:线程工厂,用来创建线程,主要是为了给线程起名字,默认工厂的线程名字:pool-1-thread-3。
- handler:拒绝策略,当线程池里线程被耗尽,且队列也满了的时候会调用。
以上就是创建线程池时用到的参数,面试中经常会有面试官问到这个问题。
请你说说IO多路复用(select、poll、epoll)
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。
(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。
网友评论