String和StringBuffer和StringBuilder的区别
==和equals
八大基本数据类型
Integer缓冲池
也叫Integer常量池(IntegerCache(静态内部类))是Java的一个优化机制,用于提高整数对象的重用和性能。范围是-128到127。最大值可以修改,最小值不能修改。在使用Integer缓冲池会有自动装箱和拆箱的操作。
工作原理:
缓存初始化:Integer第一次被使用时,会初始化这个缓存。缓存大小由JVM的启动参数或默认值确定。
对象重用:使用
Integer.valueOf(int i)
方法(或自动装箱机制)创建Integer对象时,如果请求的整数在缓存范围内,就会直接从缓存中返回该对象的引用,而不时创建一个新的对象。这样节省内存提高性能。缓存范围:默认情况下,-128到127之间的所有整数对象。
注意:
缓存池大小是有限的,超出了范围,会创建新的对象。
缓存池大小可以通过JVM的启动参数进行调整。
除了Integer之外,Byte、Short、Long也有类似的缓存机制
String常量池
是Java内存中一个特殊的存储区域,用来存储字符串常量。
①、当时用String str = "hello";
创建一个字符串时,JVM会在字符串常量池中查找是否存在该字符串。
如果存在,直接返回常量池中该字符串的引用,不会创建新的字符串对象
如果不存在,就会在常量池中创建一个新的字符串对象,返回该对象引用
②、使用new的方式,用String str = new String("hello");
创建一个字符串时。不会再常量池中查找,而是创建一个新的字符串对象。该对象内容与常量池中的内容一样,但他们时两个不同的对象。
注意:
字符串常量池的大小时有限的,可以通过JVM参数设置。
常量池中的字符串时全局共享的,避免了存储大量相同的字符串,避免内存溢出问题。
异常体系图
ThrowAble
|——error
|——exception
|——IOException
|——ClassNotFoundException
|——RuntimeException
|——算术异常
|——非法异常
|——长度界限异常
|——类型转换异常
|——空指针异常
checkedException与RuntimeExcpetion区别?
throw和throws的区别
final,finally,finalize的区别
说一下序列化和反序列化
Object类有哪些常见方法?
short s1 = 1; s1 = s1 + 1; short s1 = 1; s1 += 1;有错么?
Java的四种引用,强弱软虚
强引用,弱引用,软引用,虚引用
虚引用跟弱引用差不多,在被gc回收之前,会被放入referenceQueue中。一般用于销毁前的处理工作。
Java创建对象有几种方式?
有没有可能两个不相等的对象有相同的hashcode
两个不同的对象会有相同的hashcode这样就行成了hash冲突。以下是解决办法:
拉链法:
开放地址法:
再哈希法:
深拷贝和浅拷贝的区别是什么?
重写和重载的区别
注解
IO和NIO的区别
说一下设计模式7大原则
单一再则原则:实现类要职责单一
里氏替换原则:不要破坏继承体系
依赖倒置原则:面向接口编程
接口隔离原则:设计接口的时候要精简单一
迪米特原则:降低耦合
开放式关闭原则:对扩展开放,对修改关闭
合成复用原则:多用组合,少用继承
接口和抽象类区别?
集合体系结构
List和Set的区别
ArrayList和linkedList的区别?
ArrayList底层是数组,查询快,增删慢
LinkedList底层是链表,查询慢,增删快
ArrayList自动扩容机制
ArrayList底层是数组,默认初始长度是10,长度不够会创建一个新数组扩容1.5倍。
老数组长度+老数组长度右移一位=1.5倍
HashMap底层原理(HashSet底层原理)[重点]
HashMap是数组+链表+红黑树实现,为了提高查找效率
当链表元素超过了8,会转换成红黑树。当红黑树节点小于等于6时会退换成链表
默认负载因子为0.75,数组大小为16。数组大小*加载因子得到一个值,一旦元素存储个数超过了该值,会调用rehash方法扩容到原来的2倍。扩容会重新计算哈希值重新生成新的数组,所以扩容消耗性能。
map.put原理
计算哈希值
确定索引
检查桶是否为空
数组的该索引位置为空,直接将新节点插入到该位置
处理哈希冲突
扩容判断
map.get原理
计算哈希值
确定桶的索引
利用位运算快速定位到存储桶
遍历桶中的节点
通过链表或红黑树查找目标键
返回对应的值
HashSet的底层原理主要依赖于HashMap。
HashSet中的元素被存储为HashMap的key,value使用同一个固定的Object。由于HashMap的key是唯一的,所以HashSet不会重复元素。
元素的存储位置是根据hashcode值来决定的,所以HashSet的元素顺序是不确定的。
红黑树特点
根节点是Black
叶子节点都是Black
任一节点到叶子节点的所有路径都包含相同数目的black节点
red节点的子节点为Black
HashMap和HashTable的区别?
HashMap是线程不安全的,效率高。HashTable是线程安全的,效率低。
HashMap的key和value可以为空,HashTable不能
HashMap的父亲为AbstractMap,HashTable的父类为Dictionary
UDP与TCP的区别
udp无连接,不可靠,通信效率高
tcp面向连接,传输可靠,通信效率相对不高
说一下TCP三次握手机制,及发送的数据报文?
第一次握手:客户端发送syn包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
tcp/ip模型
OSI七层参考模型
TCP/IP模型
每层中又有那些协议
Tcp报文格式?
IP报文格式?
HTTP与TCP有关吗?
创建多线程的方式有那些
Thread与Runnable的区别
面试题: 开启一个线程是调用run方法还是start方法?
线程生命周期
新创建(New)
可运行(Runnable)
被阻塞(Blocked)
等待(Waiting)
计时等待(Timed Waiting)
终止(Terminated)
synchronized和Lock区别
synchronized是java内置关键字,Lock是java一个接口
synchronized自动上锁和解锁,Lock手动上锁和解锁
synchronized无法判断是否获取到锁,Lock可以判断
ThreadLocal
threadLocal的用法
ThreadLocal是双层map结构
内存泄漏问题:
ThreadLocalMap的Entry对ThreadLocal的引用为弱引用,ThreadLocalMap使用ThreadLocal的弱引用作为key,会被gc回收,出现key为null的情况,线程池使用时,会出现value的内存泄露。所以使用ThreadLocal就一定要使用remove
线程池
通过Executors工具类来实现,Executor,ExecutorService
工作原理:
如果线程池中的线程数小于核心线程数(corePoolSize),运行任务
如果线程数>=核心线程数但小于任务队列数,放到任务队列中
如果队列也满了,但小于最大线程数(maxPoolSize),则创建新线程来执行
如果都满了,则拒绝该任务
合理设置线程数:
cpu密集型:cpu核数+1
io密集型:cpu核数*2
中断
调用interrupte方法就是将该线程的中断标识设置为true。但是在执行wait,sleep,join的方法是,如果收到中断信号,就会抛出异常,并清除中断信号。所以应该收到异常后,捕获该异常,在异常处理部分再次中断。
静态方法 interrupted() 两个作用:
1、返回当前线程的中断状态
2、并清除中断状态,设置为false
isInterrupted 判断当前的中断状态
停止线程
volatile的boolean变量
AtomicBoolean
中断
synchronized
是Java的内建的同步机制,提供互斥的语义和可见性。当一个线程已经获得当前锁时,其它试图获取锁的线程只能等待或着阻塞在那里。
synchronized时基于一对monitorEnter/monitorExit指令来实现的。Monitor对象时同步的基本实现单元,无论时显示同步,还是隐式同步都是如此。区别就是同步代码块是通过monitorEnter/monitorExit指令来实现的,而同步方法是通过ACC_SYNCHRONIZED标志来隐式实现。
对象的结构
对象头:
mark word(对象标记):存储hashcode,锁标志位等,占8个字节
类型指针(类元信息):说明是哪个类型,4个字节
实列数据:
存放类的属性数据信息,包括父类的属性信息
对齐填充
按8的整数倍补齐
synchronized 锁升级过程
无锁
偏向锁
假如线程A拿到锁,此时线程B又要该所,由于锁被线程A拿到,则该锁为偏向锁。
为了解决只有一个线程执行同步时提高性能
轻量级锁
本质就是自旋锁(使用CAS自旋)
在偏向锁情况下,线程B争抢时发现对象头mark word中的线程ID不是线程B自己的线程ID,那么线程B就会进行CAS操作获得该锁,在该操作中有两种情况:
如果锁获取成功,直接替换mark word的线程ID为B自己的,重新偏向于其他线程(当前线程A释放了锁),该锁会保持偏向锁状态,线程A释放,线程B上位。
获取失败,则偏向锁升级为轻量级锁,此时轻量级锁保留原偏向锁的线程持有,继续执行同步代码,而正在竞争的线程B会进入自旋等待获得该轻量级锁。(在JDK6之前自旋10次,JDK6之后不固定)
重量级锁
依靠操作系统的互斥锁(mutex lock)来实现,需要切换到内核态
JMM
原子性:即一个操作或着多个操作要么全部执行并且执行的过程不会被任何因素打断,要么全部不执行。
可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量值,其他线程能过立即看到修改的值。
有序性:即程序执行的顺序按照代码的先后顺序来执行。
执行流程?
CAS
比较并交换,是一种多线程同步的原子操作。它基于硬件的原子性保证,用于解决并发环境下的数据竞争和线程安全问题。
CAS操作包括三个参数:内存地址V,旧的预期值A,要修改的值(新的值B),执行步骤如下
1、获取当前内存地址的当前值
2、比较当前值与预期值A是否相等
3、如果相等,就将内存地址的值更新为B
4、如果不相等,就不做任何操做
java.util.concurrent.atomic包提供了一系列的CAS操作类,如AtomicInteger,AtomicLong等,能过以原子方式对这些类的值进行更新和修改,实现线程安全操作。
常见并发包
concurrent
atomic
|——基本原子类AtomicInteger
|——引用类型原子类AtomicReference
locks
常见并发容器
ConcurrentHashMap
cow容器:写时复制,最终一致,读多写少
|————CopyOnWriteArrayList
|————CopyOnWriteArraySet
并发队列
|——有界队列 ArrayBlockingQueue
|——无界队列 LinkedBlockingQueue
|——无界阻塞队列 PriorityBlockingQueue
|——不存储元素的阻塞队列 SynchronousQueue
countdownlatch,CycleBarrier,Semaphore
AQS
是一个用于构建锁和同步器的基础框架,它通过先进先出的等待队列管理多个线程的同步操作。例如:ReentrantLock,Semaphore,CountDownLatch。
AQS使用一个volatile的int类型的成员变量来表示同步状态(0空闲,1占用)。通过内置的FIFO队列来完成资源获取的排队工作,将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配,通过CAS完成State值的修改。
volatile
volatile是java提供的一种轻量级的同步机制。Java语言包含两种内在同步机制:同步块(或方法)和volatile变量,相当于synchronized(通常称为重量级锁),volatile更轻量级,因为他不会引起线程上下文的切换和调度。但是volatile变量的同步性差,而且使用也更容易出错。
volatile保证可见性,有序性。不保证原子性。
ConcurrentHashMap
ConcurrentHashMap采用了数组+Segment(分段锁)来实现。
分段锁类似于HashMap的结构,即内部有一个Entry数组,数组中的每个元素又是一个链表,同时又是ReentrantLock。
ConcurrentHashMap使用分段锁技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用访问其中一个数据的时候,其他段的数据也可以被其他线程访问,能构实现真正的并发。
JDK7为Segment,JDK8为CAS
wait与sleep的区别
wait必须要在synchronized的前提下使用,sleep不需要
wait在wait过程中会释放锁,sleep不会
wait时Object的方法,sleep时Thread的方法