JAVA面试终结版

zu1 、hashmap的底层,和hashtable,hashset有什么区别?currenthashtable的底层?
hashmap的实现方式数组加链表,在jdk1.8以后使用数组加二叉树的结构。
hashcode采用31的原因是,因为可以利用移位操作代替乘法和减法操作,hashmap的初始容量为16加载因子为0.75。加载因子越大,就是启用扩容的阈值越大,这表明hashmap所占的内存越少,但是某一数组上挂载的链表长度越长,所以搜索速度越慢。hashset理论实现和hashmap是相同的,只是hashset的value值是确定的,而且hashmap属于map而hashset属于collection。
hashmap是线程不安全的,hashtable是线程安全的,并且hashtable的实现方式是拉链法。另外hashmap是快速失败的,而hashtable不是,hashtable的键可以为null,但是hashtable不允许。
currenthashtable 和hashmap一样都是线程安全的,但是currenthashtable是对每一个段数据都配有一个锁,而hashtable如果发生写操作时,将会对整个表加锁,相对于currenthashmap而言,可靠性要高,但是速度慢。
concurrenthashmap是二级hashmap,第一层维护segment,第二层是每个segment维护的元素组成的hashmap结构。
一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。
ConcurrentHashMap的get操作
Segment的get操作实现非常简单和高效。先经过一次再哈希,然后使用这个哈希值通过哈希运算定位到segment,再通过哈希算法定位到元素,代码如下:

public V get(Object key) {
    int hash = hash(key.hashCode());
    return segmentFor(hash).get(key, hash);
}

get方法定义成volatile的变量,能够在线程之间保持可见性,能够被多线程同时读,并且保证不会读到过期的值,但是只能被单线程写(有一种情况可以被多线程写,就是写入的值不依赖于原值),在get操作里只需要读不需要写共享变量count和value,所以可以不用加锁。之所以不会读到过期的值,是根据java内存模型的happen before原则,对volatile字段的写入操作先于读操作,即使两个线程同时修改和获取volatile变量,get操作也能拿到最新的值,这是用volatile替换锁的经典应用场景。

transient volatile int count;
volatile V value;

在定位元素的代码里我们可以发现定位HashEntry和定位Segment的哈希算法虽然一样,都与数组的长度减去一相与,但是相与的值不一样,定位Segment使用的是元素的hashcode通过再哈希后得到的值的高位,而定位HashEntry直接使用的是再哈希后的值。其目的是避免两次哈希后的值一样,导致元素虽然在Segment里散列开了,但是却没有在HashEntry里散列开。

hash >>> segmentShift) & segmentMask//定位Segment所使用的hash算法
int index = hash & (tab.length - 1);// 定位HashEntry所使用的hash算法

ConcurrentHashMap的Put操作
由于put方法里需要对共享变量进行写入操作,所以为了线程安全,在操作共享变量时必须得加锁。Put方法首先定位到Segment,然后在Segment里进行插入操作。插入操作需要经历两个步骤,第一步判断是否需要对Segment里的HashEntry数组进行扩容,第二步定位添加元素的位置然后放在HashEntry数组里。
是否需要扩容。在插入元素前会先判断Segment里的HashEntry数组是否超过容量(threshold),如果超过阀值,数组进行扩容。值得一提的是,Segment的扩容判断比HashMap更恰当,因为HashMap是在插入元素后判断元素是否已经到达容量的,如果到达了就进行扩容,但是很有可能扩容之后没有新元素插入,这时HashMap就进行了一次无效的扩容。
如何扩容。扩容的时候首先会创建一个两倍于原容量的数组,然后将原数组里的元素进行再hash后插入到新的数组里。为了高效ConcurrentHashMap不会对整个容器进行扩容,而只对某个segment进行扩容。

ConcurrentHashMap的size操作
ConcurrentHashMap的做法是先尝试2次通过不锁住Segment的方式来统计各个Segment大小,如果统计的过程中,容器的count发生了变化,则再采用加锁的方式来统计所有Segment的大小。那么ConcurrentHashMap是如何判断在统计的时候容器是否发生了变化呢?使用modCount变量,在put , remove和clean方法里操作元素前都会将变量modCount进行加1,那么在统计size前后比较modCount是否发生变化,从而得知容器的大小是否发生变化。

2 、spring 的aop你怎么看?Spring的aop怎么实现?Spring的aop有哪些实现方式
aop是spring两大特点中的一个,aop翻译过来是面向切面,而与面向对象不同的是面向切面是一个寄生编程方式。主要包括,切入点,连接点,切面,织入,通知。
aop动态代理的方法可以使用jdk动态代理或者CGLIB动态代理,前者基于接口,后者基于子类。
xml开发例子:


	<bean id="helloworld" class="myaop.HelloWorldImpl1">
	</bean>
	<bean id="printtime" class="myaop.printtime"></bean>
	<aop:config>
		<aop:aspect id="dotime" ref="printtime">切面类
			<aop:pointcut id="adddoMethod"
				expression="execution(* myaop.HelloWorldImpl1.do*(..))" />运行时
			<aop:before method="syso" pointcut-ref="adddoMethod" />
			前一个是切面的方法,后一个是被切的方法,意思是在adddpmethod之前运行syso方法,是poincut。
			<aop:after method="syso" pointcut-ref="adddoMethod" />
			
		</aop:aspect>
				<aop:aspect id="printtime" ref="printtime">
			<aop:pointcut id="addprintMethod"
				expression="execution(* myaop.HelloWorldImpl1.print*(..))" />
			<aop:before method="logging" pointcut-ref="addprintMethod" />
		</aop:aspect>
	</aop:config>
</beans>

3 、索引有什么用?索引失效问题?索引分类?用途?
https://blog.csdn.net/timer_gao/article/details/78013826
传统无索引情况下,如果需要查询某一字段的数据时需要
https://blog.csdn.net/waeceo/article/details/78702584
4 、数据库引擎,存储结构
mysql常用数据引擎有
InnoDB 默认引擎,支持事务,支持外键,支持行级锁。mysql在运行innodb时会再内存中建立缓冲池,用于缓冲数据和索引。但该引擎不支持FULLTEXT类型的索引,而且不保存行数,因此当select count(*) form table需要扫描全表。另外索引采用是聚集索引,因此必须确定primary key,如果用户不指定,将自动选定一个字段作为主键,如果不存在这种列,将使用隐含字段。
Isam
Myisam isam的扩展版本,没有事务,索引采用非聚集索引,可以没有主键。
memory 与redis类似,是内存数据库,使用hash索引

myisam和innodb选择?
innodb
1 可靠性要求高,需要事务
2 插入和查询都很频繁
myisam
1 没有事务
2 做count运算
3 插入不频繁,查询频繁

5 、spring 的理解?bean的实现方式?bean的生命周期,作用域
1 core 是最基础的部分,主要提供ioc功能,基础概念是bean工厂
2 context 构筑于core包之上,国际化,事务传播,资源加载,以及透明创建上下文
3 aop 面向切面编程的包
4 dao 提供了jdbc的抽象层,并且提供了事务管理
5 orm 提供了hibernate,mybaits的接口
6 mvc提供了mvc 的实现
7 web 提供了对structs2 或者webword 的接口
bean的实现详见https://blog.csdn.net/wuzhengfei1112/article/details/74056324
bean的创建分为两部分,
第一部是解析xml
第二部是生成beanfactory
bean的生命周期和作用域
生命周期:Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期
下图是singleton的生命周期:
Alt text
作用域:singleton,prototype,session,globalsession,request

6、快排和归并和堆排的算法。
快排

public class QuickSort {
	public static void quickSortHelp(int[] arr) {
		quickSort(arr,0, arr.length-1);
	}
	public static void quickSort(int[] arr,int low, int high) {
		if(low<high) {
			int partition = partition(arr,low,high);
			quickSort(arr,low, partition-1);
			quickSort(arr,partition+1, high);
		}
		
	}
	public static int partition(int[] arr,int low,int high) {
		while(low<high) {
			while(arr[high]>=arr[low]&&low<high){
				high--;
			}
			Swap(arr,high,low);
			while(arr[low]<=arr[high]&&low<high) {
				low++;
			}
			Swap(arr,high,low);
		}
		return low;
	}
	public static void Swap(int[] arr,int high,int low) {
		int temp = arr[low];
		arr[low] =arr[high];
		arr[high] = temp;
	}
	public static void main(String[] args) {
		int[] array = { 2, 8, 5, 6, 10, 5, 4, 6, 11, 15, 3 };
		quickSortHelp(array);
		for (int s : array) {
			System.out.println(s);
		}
	}
}

7、代理模式

   package daili;

public interface Account {
	//查询功能
    public void queryAccount();
    //修改功能
    public void updateAccount();

}
package daili;

public class AccountImpl implements Account {
	 @Override
	    public void queryAccount() {
	        System.out.println("委托类的查询方法...");
	    }
	 
	    @Override
	    public void updateAccount() {
	        System.out.println("委托类的修改方法.....");
	    }
}
package daili;

public class AccountProxy implements Account {
	 private AccountImpl accountImpl;
	 
	    /**
	     * 
	     * @Title: AccountProxy
	     * @Description: 重写默认的构造函数。真正执行的业务对象是accountImpl
	     * @param: @param accountImpl
	     * @throws
	     */
	    public AccountProxy(AccountImpl accountImpl){
	        this.accountImpl=accountImpl;
	    }
	    @Override
	    public void queryAccount() {
	        System.out.println("查询业务处理之前...");
	        accountImpl.queryAccount();
	        System.out.println("查询业务处理之后....");
	    }
	 
	    @Override
	    public void updateAccount() {
	        System.out.println("修改业务处理之前...");
	        accountImpl.queryAccount();
	        System.out.println("修改业务处理之后....");
	 
	    }

}
package daili;

public class Test {

	 public static void main(String[] args) {
	        AccountImpl accountImpl=new AccountImpl();
	        AccountProxy accountProxy=new AccountProxy(accountImpl);
	        accountProxy.queryAccount();
	        accountProxy.updateAccount();
	 
	    }

}

动态代理https://www.cnblogs.com/baizhanshi/p/6611164.html
aop主要使用动态代理和反射

8、线程锁有哪些?数据库锁有哪些
synchronize,volatile,lock
行锁,表锁,悲观锁,乐观锁
表锁:行共享,行排他,共享锁,共享行排他,排他
https://www.cnblogs.com/sessionbest/articles/8689071.html
9、线程池类型?线程池设置参数,线程返回值
** ScheduleThreadPool**

** SingleThreadExecutor**

FixedThreadPool

CachedThreadPool

上面的线程池都是改变threadpoolexecutor参数实现,就是定制的threadpool,当然可以自己实现
常用threadpoolexecutor
int corePoolSize,核心线程数
int maximumPoolSize,最大维护线程池
long keepAliveTime,超过核心池数量的线程的时间
TimeUnit unit,时间单位
BlockingQueue workQueue,
1SynchronousQueue
2LinkedBlockingQueue
3ArrayBlockingQueue
4DelayQueue
10 、分页怎么实现的
分页有两种方式,一种物理分页,即使用limit 。另一种是使用游标,也称为逻辑分页

11、三次握手四次挥手都做了什么
三次握手:
1 TCP服务器首先创建传输控制块TCB,时刻准备接受客户进程的连接请求,进入LISTEN(监听状态)
2 TCP客户进程也先创建传输控制块TCB,然后向服务器发送连接请求,此时报文同部位的SYN=1,同时选择一个初始序列号seq=x;此时tcp客户端进入到SYN-SENT阶段。
3 TCP服务端收到连接请求,如果同意连接则,发出确认报文,SYN=1,ACK=1,seq=y,ack=x+1,此时服务器进入SYN-RCVD状态
4 TCP客户端收到确认后向服务器发出确认,报文ACK=1,seq=x+1,ack=y+1;
5 进入establish状态
进行三次握手而不是两次是因为如果发生延时在客户端向服务器端发送请求时,那么服务器将直接和客户机建立连接,而此时客户机可能已经不想要了,造成资源浪费,而进行三次握手相当于客户机向服务器再次确认需要建立连接,保证了实时性和有效性

四次挥手:
1原本是establish状态,客户端和服务端
2客户端主动关闭,发出关闭请求FIN=1,seq=u,进入FIN-WAIT-1状态
3服务器收到关闭请求,如果同意,发出ACK=1,seq=v,ack=u+1,进入close-wait状态
4客户机收到后进入FIN-WAIT-2状态
5服务器再次发出FIN=1,ACK=1,seq=w,ack=u+1,进入LAST-ACK
6客户机收到后发出ACK=1,seq=u+1.ack=w+1,进入TIME-WAIT状态
7服务器收到后关闭
8客户端等待2MSL关闭

等待2MSL
等待2MSL是因为首先保证客户端向服务发送的确认报文,服务器可以收到,如果没收到,服务器会再发一个确认报文,在这个时间内客户机人处于time-wait状态,可以重传确认报文
第二点,是保证在这个时间内,这个旧的报文段可以从网络中消失,保证新的报文的有效性。
建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
握手三次挥手四次问题
关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次
参考:https://blog.csdn.net/qzcsu/article/details/72861891

12、java虚拟机内存管理,类的加载和双亲委派
堆,栈,静态成员
堆,本地方法栈,程序计数器,jvm栈,方法区。其中本地方法栈,jvm栈和程序计数器是不共享的,而堆和方法区是共享的。
本地方法栈主要是其他编码语言开发的一些方法和接口
jvm栈是局部的变量
程序计数器是字节码记录程序以及方法的入口
方法区是,类加载时存储静态成员的区域,包括编译后的代码,常量,静态常量,类信息。
堆是对象储存的区域,根据新生代和老生代分为三个区域,两个servior,一个eden,一个老生代区
类加载过程
加载连接和初始化。其中连接分为验证,准备,和解析
验证:确保加载的类信息符合JVM规范,没有安全方面的问题
准备:正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法去中进行分配
解析:虚拟机常量池的符号引用替换为字节引用过程
加载器有,启动类加载器,扩展类加载器,应用程序类加载器,用户自定义类加载器
双亲委派模型是指:当一个类加载器收到加载任务时,并不会立刻执行加载,而是把类加载向父加载器抛出,如果父类处理不了就继续向上抛出,直到顶层类加载器也处理不了,就尝试自己执行加载任务,这些做的好处是永远只加载唯一的类。

13、垃圾回收,回收什么?什么时候回收?怎样发现?怎样清理?新生代老生代永久代?
垃圾回收是回收对象 和方法区中的是不使用的对象,回收时间新建一个对象后,如果eden已满,就会在用minor gc回收不常用对象。如果年老代的满的时候,利用fullgc,进行垃圾回收。
发现包括两种方法:
一种是计数法,每当一个地方引用对象时,计数器值加一,引用失效计数器减1,任何时刻计数器为0的对象表示不再被使用,但是由于这种方法解决不了相互引用问题,所以jvm不使用这种方法。
另一种是可达性分析法,即以一系列的gc root的对象为初始对象,从这些节点向下搜索,搜索走过的路径为引用链,当一个对象到gcroot没有任何引用,即不可达时,则证明此对象不可达。可以选用方法区的常量应用对象,虚拟机栈,本地方法栈为gcroots。
清理:
标记-清除:这种方法通过上述的发现方法后,利用清除方法对对象进行清除,但是这种方法会留下大量的碎片,这可能导致需要连续内存时需要重复执行低效的算法。
复制算法:将内存分成两块,每次用一块内存,如果内存用完后,将存活对象复制到另一块中,而使用过的内存空间直接清理。但是这种方法非常耗费内存,因为要分成两块。一般利用这种算法清理新生代。
压缩算法:将活动的对象都向另一端移动,清理边界以外的内存。
结合上面三种基本算法:目前商用虚拟机采用分代收集算法。对于大批对象死去,少量存活的新生代使用复制算法,而对于存活率高的老年代使用压缩或者标记清楚
常见收集器
串行收集器,单条线程收集,暂停其他线程工作
并行收集器,多线程,服务器收集。
CMS并发收集器多线程标记清除,不暂停
G1 收集器多线程,主线程暂停并行,否则并发,取消物理层面的新生代和年老代的划分,并且有巨型对象直接放置在年老代
参考https://www.cnblogs.com/ASPNET2008/p/6496481.html

	新生代利用复制算法,而老生代使用标记清除或者压缩算法,为fullgc。新生代有三个区,两个surivior,一个eden,比例为1:1:8。新建的对象一般位于eden中,如果在第一次垃圾回收后,仍然处于活跃状态,则将其放入surivior中,如果幸存15次,则将这个对象移入到老生代。surivior一个是from,一个是to,每一次回收都会清空eden,并将活动的surivior中的对象从一个复制到另一个。

14、表的insert,delete,update,select,inner join on,left join on,right join on,以及sort 等基本操作,以及一对多,一对一,多对多的处理。

15、 事务的隔离级别和传输特性
三个问题,脏读,不可重复读,幻读
四种隔离级别
未提交读,不解决问题
提交读,解决脏读
可重复读,解决脏读和不可重复读
序列化,解决脏读,不可重复读,幻读
八种传输特性
如果有事务则使用事务如果没有则不使用 support
如果有事务使用事务如果没有则创建事务 requested
如果有事务使用事务,如果没有抛出异常
如果有事务挂起当前事务,另外创建事务,没有事务创建事务
如果有事务则挂起当前事务,不使用事务,没有事务也不创建
如果有事务则挂起当前事务,并抛出异常
事务嵌套

16、什么是redis?解决什么问题?redis的淘汰策略和调优,持久化?穿透和雪崩分别指什么?怎么处理?
Redis是一款k-v内存数据库,可以解决高并发和高性能问题
redis的淘汰策略主要有
从过期数据中剔除使用最少的数据 volatile-lru
从过期数据中剔除随机数据 volatile-lru
从所有数据中剔除使用频率最低的数据allkeys-lru
从所有数据中剔除随机数据 allkeys-random
从过期中选择即将过期数据 volatile-ttl
禁止剔除数据 noeviction
快照和aof·
快照是将数据直接保存,aof是利用日志保存
穿透是指黑客一直访问内存数据库中不存在的数据,导致这些数据都落在了硬盘数据库中,导致数据库压力增大,从而宕机
雪崩是指数据量过大,或者内存数据库有部分宕机,导致内存数据库处理不了这么大数据量,使得这些请求都在硬盘数据库中,使得服务器宕机
雪崩的解决方法
前:建立完善的redis集群,以及良好的内存更新方案,和适合的备份方案
中:使用访问控制系统,限流
后:快速恢复内存数据库

17、接口和抽象类的区别,注意JDK8的接口可以有实现。
1接口中所有的方法都是抽象的,但是抽象类中有普通方法
2可以实现多个接口但是只能继承一个类
3接口只有方法名,抽象类可以有方法体,但是在jdk1.8接口也可以有方法体,但必须是default修饰的。
4接口没有构造器,而抽象函数有构造器
5接口只能用public修饰,但是抽象类可以用default,public,prodected修饰
6接口中没有main方法,但是抽象类中可以有
7接口中添加方法,必须修改实现它的所有类,但是抽象类可以默认方法。

18、Java序列化的方式,如何在序列化过程中使得某些元素保密
序列化:对象转为二进制码传输
反序列化:将二进制编码转换回对象

19、什么是反射?为什么使用反射?你平时在哪些框架遇见过反射?
在运行时动态加载类。
Java反射机制主要提供了以下功能:在运行时构造一个类的对象;判断一个类所具有的成员变量和方法;调用一个对象的方法;生成动态代理。反射最大的应用就是框架
Java反射的主要功能:
1确定一个对象的类
2取出类的modifiers,数据成员,方法,构造器,和超类.
3找出某个接口里定义的常量和方法说明.
4创建一个类实例,这个实例在运行时刻才有名字(运行时间才生成的对象).
5取得和设定对象数据成员的值,如果数据成员名是运行时刻确定的也能做到.
6在运行时刻调用动态对象的方法.
7创建数组,数组大小和类型在运行时刻才确定,也能更改数组成员的值.
反射的应用很多,很多框架都有用到
spring 的 ioc/di 也是反射….
javaBean和jsp之间调用也是反射….
struts的 FormBean 和页面之间…也是通过反射调用….
JDBC 的 classForName()也是反射……
hibernate的 find(Class clazz) 也是反射….
反射还有一个不得不说的问题,就是性能问题,大量使用反射系统性能大打折扣。
**20、jdbc的使用,jdbc连接池,有什么封装好的jdbc工具

<!-- c3p0连接池配置 -->
     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
          <!-- 用户名-->
          <property name="user" value="${username}"/>
          <!-- 用户密码-->
          <property name="password" value="${password}"/>
          <property name="driverClass" value="${driver_class}"/>
          <property name="jdbcUrl" value="${url}"/>
 
           <!--连接池中保留的最大连接数。默认值: 15 --> 
          <property name="maxPoolSize" value="20"/>
          <!-- 连接池中保留的最小连接数,默认为:3-->
          <property name="minPoolSize" value="2"/>
          <!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3-->
          <property name="initialPoolSize" value="2"/>
 
          <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 --> 
          <property name="maxIdleTime">60</property>
          
          <!-- 当连接池连接耗尽时,客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒。默认: 0 --> 
          <property name="checkoutTimeout" value="3000"/>
          
          <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 --> 
          <property name="acquireIncrement" value="2"/>
 
         <!--定义在从数据库获取新连接失败后重复尝试的次数。默认值: 30 ;小于等于0表示无限次--> 
          <property name="acquireRetryAttempts" value="0"/>
 
          <!--重新尝试的时间间隔,默认为:1000毫秒--> 
          <property name="acquireRetryDelay" value="1000" />
 
          <!--关闭连接时,是否提交未提交的事务,默认为false,即关闭连接,回滚未提交的事务 --> 
          <property name="autoCommitOnClose">false</property>
 
          <!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试使用。默认值: null --> 
          <property name="automaticTestTable">Test</property>
 
          <!--如果为false,则获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常,但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认: false--> 
          <property name="breakAfterAcquireFailure">false</property>
 
          <!--每60秒检查所有连接池中的空闲连接。默认值: 0,不检查 --> 
          <property name="idleConnectionTestPeriod">60</property>
          <!--c3p0全局的PreparedStatements缓存的大小。如果maxStatements与maxStatementsPerConnection均为0,则缓存不生效,只要有一个不为0,则语句的缓存就能生效。如果默认值: 0--> 
          <property name="maxStatements">100</property>
          <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。默认值: 0 --> 
          <property name="maxStatementsPerConnection"></property>
     </bean>

21、日志的实现方式,安全的实现方式?
Java Logging API(Oracle)—— Java默认的日志框架
Log4j(Apache)——开源日志框架
Logback(Logback Project)——开源项目,被设计成Log4j版本1的后续版本 tinylog(tinylog)——轻量级开源logger
22、一共设计了多少表,每个表的字段是什么?mysql的优化手段?
管理员表 id,用户名,密码
用户表 id,用户名,密码,帖子数
博客表 id, 博客名,博客详情,用户外键
评论表 id,评论内容,评论时间,外键评论用户,外键博客用户名
登录人员表 id ,登录时间,登录次数。外键用户

mysql 优化的方法:

23、hibernate的几种状态

24、多线程Java实现多线程有哪几种方式。Callable和Future的了解
继承Thread,实现runnable接口
之所以又有Callable和Future是因为前两种方式并没有返回值,为了获得返回值,可以采用callable和future,或者callable和futuretask。其他获得线程返回值的方法是共享变量,或者利用wait和notify和notifyall实现线程间的通信。

package mythread2;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

class SumTask implements Callable<Long> {

	@Override
	public Long call() throws Exception {

		long sum = 0;
		for (int i = 0; i < 9000; i++) {
			sum += i;
		}

		return sum;
	}
}

public class CallableDemo {
	public static void main(String[] args) throws ExecutionException, InterruptedException {
	FutureTask<Long> futureTask=new FutureTask<>(new SumTask());
	Executor executor=   Executors.newSingleThreadExecutor();
	executor.execute(futureTask);
	System.err.println(futureTask.get());
		try {
			System.err.println();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

25、Lock接口有哪些实现类,使用场景是什么。可重入锁的用处及实现原理,写时复制的过程,读写锁,分段锁(ConcurrentHashMap中的segment)。悲观锁,乐观锁,优缺点,CAS有什么缺陷,该如何解决。ABC三个线程如何保证顺序执行。
lock 接口下有重入锁和读写锁两个,重入锁的使用场景和synchronize类似,但是具有更强大的功能,就是互斥锁。
读写锁,是将锁分为读锁和写锁,一般情况下,写锁只能由一个线程持有,读锁由多个线程持有,并且读读共享,读写互斥,写写互斥,即写的时候,其他线程不允许写或读,读的时候,其他线程不允许写。
悲观锁,就是不管是否发生多线程冲突,只要存在这种可能,就每次访问都加锁,加锁就会导致锁之间的争夺,有争夺就会有输赢,输者等待。 syncrhoized是一种独占锁,即:占用该锁的线程才可以执行,申请该锁的线程就只能挂起等待,直到占用锁的线程释放锁才唤醒,拿到锁并执行。由于在进程挂起和恢复执行过程中存在着很大的开销,并且当一个线程正在等待锁时,它不能做任何事。所以syncrhoized是一种悲观锁,凡是用syncrhoized加了锁的多线程之间都会因锁的争夺结果导致挂起、唤醒等开销。
乐观锁获得锁后一直持有锁以防本线程再次申请该锁造成无谓的解锁再加锁开销,或者假设没有冲突而去完成同步代码块如果冲突再循环重试,或者采取申请锁失败后不立刻挂起而是稍微等待再次尝试获取 等待策略,以减少线程因为挂起、阻塞、唤醒(发生CPU的调度切换) 而造成的开销。偏向锁、轻量级锁(CAS轮询)、自旋锁 就是基于上述思路的乐观锁。
在多线程的加锁机制中,JVM会首先尝试乐观锁,失败后才调用悲观锁。
CAS(Compare-and-Swap)实现乐观锁的手段,通过轮询实现乐观锁
目前大部分锁都是利用cas,如atomic类,以及lock底层,synchronize未转换为重量锁之前一直使用cas的手段。
cas的缺点:只能保证变量的原子性不能保证代码块的原子性
对cpu资源有压力
ABA问题,利用版本号解决
ABC三个线程如何保证顺序执行:用join解决,让并行变为串行。

    package mythread2;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class mylock {
	static Lock lock = new ReentrantLock();

	public static void main(String[] args) throws InterruptedException {
		mythread2 mythread2 = new mythread2();
		mythread1 mythread1 = new mythread1(mythread2);
		
		mythread1.start();
		mythread2.start();

	}
}

class mythread1 extends Thread {
	mythread2 mythread2 = new mythread2();

	public mythread1(mythread2 mythread2) {
		// TODO Auto-generated constructor stub
		this.mythread2=mythread2;
	}

	@Override
	public void run() {
		for (int i = 0; i < 1000; i++) {
			try {
				mythread2.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			mylock.lock.lock();

			System.out.print("国");
			System.out.print("亲");
			System.out.print("节");
			System.out.print("快");
			System.out.print("乐");
			System.out.println();
			mylock.lock.unlock();
		}

	}
}

class mythread2 extends Thread {

	@Override
	public void run() {
		for (int i = 0; i < 1000; i++) {
			mylock.lock.lock();
			System.out.print("好");
			System.out.print("运");
			System.out.print("连");
			System.out.print("连");
			System.out.print("连");
			System.out.println();
			mylock.lock.unlock();
		}
	}
}

重入锁reentrantlock和synchronize的区别

  1.  ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
    
  2.  ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
    
  3.  ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。
    

重入锁使用

 package mythread2;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class mylock {
	static Lock lock = new ReentrantLock();
	public static void main(String[] args) {
		new mythread1().start();
		new mythread2().start();

	}
}
class mythread1 extends Thread {

	@Override
	public void run() {
		for (int i = 0; i < 1000; i++) {
			mylock.lock.lock();
				System.out.print("国");
				System.out.print("亲");
				System.out.print("节");
				System.out.print("快");
				System.out.print("乐");
				System.out.println();
				mylock.lock.unlock();
		}

	}
}
class mythread2 extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 1000; i++) {
			mylock.lock.lock();
			System.out.print("好");
			System.out.print("运");
			System.out.print("连");
			System.out.print("连");
			System.out.print("连");
			System.out.println();
			mylock.lock.unlock();
		}
	}
}

26、线程的状态都有哪些。sleep和wait的区别。notify和notifyall的区别。ThreadLocal的了解,实现原理
新建状态,就绪状态,运行状态,阻塞状态,死亡状态,五种
阻塞状态又分为三种:等待阻塞(wait),同步阻塞(synchronize),其他阻塞(sleep,join以及io)
27、Jvm的参数设置
CATALINA_OPTS="
-server :一般应用于服务器端,启动慢,内存管理效率高,对应的是-client 应用于客户端,启动快,但是内存管理效率低
-Xms6000M 初始java堆的大小,一般将其设置为和xmx相同大小,避免jvm反复申请内存而导致性能起伏
-Xmx6000M 最大堆大小,如果应用程序内存大于该值就会使得jvm奔溃,一般设置为内存的80%
-Xss512k 栈大小,在jdk5以前设置为256,5以后设置为1m。减小此值将会容纳更多的线程,但是也会导致outofmemory,一般不设置为1m,256够用
-XX:NewSize=2250M
新生代堆大小,新生代堆包括eden,和survior,大小比一般为8:1:1
-XX:MaxNewSize=2250M
最大新生代堆大小
-XX:PermSize=128M
永久代堆大小
-XX:MaxPermSize=256M
永久代最大堆大小
-XX:+AggressiveOpts
加入最新的优化技术
-XX:+UseBiasedLocking
使用优化锁
-XX:+DisableExplicitGC
不允许使用system.gc防止性能不懂
-XX:+UseParNewGC
对新生代使用并行回收
-XX:+UseConcMarkSweepGC
年老代并行回收
-XX:MaxTenuringThreshold=31
升级为年老代的计数值
-XX:+CMSParallelRemarkEnabled

-XX:+UseCMSCompactAtFullCollection

-XX:LargePageSizeInBytes=128m
分页大小
-XX:+UseFastAccessorMethods
get,set方法转化为本地编码
-XX:+UseCMSInitiatingOccupancyOnly

-Duser.timezone=Asia/Shanghai
时区设置
-Djava.awt.headless=true"
-XX:NewRatio 4 表示年轻代比年老代为1:4

28、红黑树和b树,二叉查找树,堆,最大堆和最小堆
红黑树是一种自平衡二叉树
b树balance多叉树,b+树比b树多了同级引用
二叉查找树的性质是必须是没有重复的数字,所以适合map,当然是变形以后,其实二叉查找树的建立类似于插入排序。
**堆是满二叉树
29、内存屏障是什么
内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。Java编译器也会根据内存屏障的规则禁止重排序。
内存屏障可以被分为以下几种类型
LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。 在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。
有的处理器的重排序规则较严,无需内存屏障也能很好的工作,Java编译器会在这种情况下不放置内存屏障。
为了实现上一章中讨论的JSR-133的规定,Java编译器会这样使用内存屏障。
为了保证final字段的特殊语义,也会在下面的语句加入内存屏障。
x.finalField = v; StoreStore; sharedRef = x;
https://www.cnblogs.com/chenyangyao/p/5269622.html
30、Object类下的方法
tostring
equals
hashcode
wait
notify
notifyall
getclass
finalize
clone
31、bio、nio和aio的区别
bio 同步阻塞
nio 异步阻塞
aio 异步非阻塞
详情:https://blog.csdn.net/huangwenyi1010/article/details/75577091
32、Synchronize原理?lock原理?volitile原理?三者区别?i++线程安全?在1.6后synchronize的性能提升?
synchronize 是jvm控制的内置锁
lock是编程实现的显式锁
volitile是关键字
synchronize 和Reentrantlock都是同步的,而且都是阻塞式同步,并且都是可重入锁。synchronize是jvm实现的,而lock是api层面实现的,而且需要lock和unlock联合try…finally使用。同时synchronize是非公平锁,lock默认是非公平锁,但是可以通过设置,将lock转为公平锁。synchronize是独享锁,reentrantlock也是独享锁,但是readwritelock的读共享锁写是独享锁,通过aqs实现。同时lock等待可以中断,但是synchronize不行。

在jdk1.6,加入了偏向锁,轻量级锁,自旋锁和重量级锁,随着并发程度的增大,逐渐升级但是不能降级。
33、生产者和消费者模式

synchronized、wait和notify 方法实现

package producerConsumer;
//wait 和 notify
public class ProducerConsumerWithWaitNofity {
    public static void main(String[] args) {
        Resource resource = new Resource();
        //生产者线程
        ProducerThread p1 = new ProducerThread(resource);
        ProducerThread p2 = new ProducerThread(resource);
        ProducerThread p3 = new ProducerThread(resource);
        //消费者线程
        ConsumerThread c1 = new ConsumerThread(resource);
        //ConsumerThread c2 = new ConsumerThread(resource);
        //ConsumerThread c3 = new ConsumerThread(resource);
    
        p1.start();
        p2.start();
        p3.start();
        c1.start();
        //c2.start();
        //c3.start();
    }
    
    
    
}
/**
 * 公共资源类
 * @author 
 *
 */
class Resource{//重要
    //当前资源数量
    private int num = 0;
    //资源池中允许存放的资源数目
    private int size = 10;

    /**
     * 从资源池中取走资源
     */
    public synchronized void remove(){
        if(num > 0){
            num--;
            System.out.println("消费者" + Thread.currentThread().getName() +
                    "消耗一件资源," + "当前线程池有" + num + "个");
            notifyAll();//通知生产者生产资源
        }else{
            try {
                //如果没有资源,则消费者进入等待状态
                wait();
                System.out.println("消费者" + Thread.currentThread().getName() + "线程进入等待状态");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 向资源池中添加资源
     */
    public synchronized void add(){
        if(num < size){
            num++;
            System.out.println(Thread.currentThread().getName() + "生产一件资源,当前资源池有" 
            + num + "个");
            //通知等待的消费者
            notifyAll();
        }else{
            //如果当前资源池中有10件资源
            try{
                wait();//生产者进入等待状态,并释放锁
                System.out.println(Thread.currentThread().getName()+"线程进入等待");
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
/**
 * 消费者线程
 */
class ConsumerThread extends Thread{
    private Resource resource;
    public ConsumerThread(Resource resource){
        this.resource = resource;
    }
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            resource.remove();
        }
    }
}
/**
 * 生产者线程
 */
class ProducerThread extends Thread{
    private Resource resource;
    public ProducerThread(Resource resource){
        this.resource = resource;
    }
    @Override
    public void run() {
        //不断地生产资源
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            resource.add();
        }
    }
    
}

方式二:lock和condition的await、signalAll

package producerConsumer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 使用Lock 和 Condition解决生产者消费者问题
 * @author tangzhijing
 *
 */
public class LockCondition {
        public static void main(String[] args) {
            Lock lock = new ReentrantLock();
            Condition producerCondition = lock.newCondition();
            Condition consumerCondition = lock.newCondition();
            Resource2 resource = new Resource2(lock,producerCondition,consumerCondition);
            
            //生产者线程
            ProducerThread2 producer1 = new ProducerThread2(resource);
            
            //消费者线程
            ConsumerThread2 consumer1 = new ConsumerThread2(resource);
            ConsumerThread2 consumer2 = new ConsumerThread2(resource);
            ConsumerThread2 consumer3 = new ConsumerThread2(resource);
            
            producer1.start();
            consumer1.start();
            consumer2.start();
            consumer3.start();
        }
}
/**
 * 消费者线程
 */
class ConsumerThread2 extends Thread{
    private Resource2 resource;
    public ConsumerThread2(Resource2 resource){
        this.resource = resource;
        //setName("消费者");
    }
    public void run(){
        while(true){
            try {
                Thread.sleep((long) (1000 * Math.random()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            resource.remove();
        }
    }
}
/**
 * 生产者线程
 * @author tangzhijing
 *
 */
class ProducerThread2 extends Thread{
    private Resource2 resource;
    public ProducerThread2(Resource2 resource){
        this.resource = resource;
        setName("生产者");
    }
    public void run(){
        while(true){
                try {
                    Thread.sleep((long) (1000 * Math.random()));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                resource.add();
        }
    }
}
/**
 * 公共资源类
 * @author tangzhijing
 *
 */
class Resource2{
    private int num = 0;//当前资源数量
    private int size = 10;//资源池中允许存放的资源数目
    private Lock lock;
    private Condition producerCondition;
    private Condition consumerCondition;
    public Resource2(Lock lock, Condition producerCondition, Condition consumerCondition) {
        this.lock = lock;
        this.producerCondition = producerCondition;
        this.consumerCondition = consumerCondition;
 
    }
    /**
     * 向资源池中添加资源
     */
    public void add(){
        lock.lock();
        try{
            if(num < size){
                num++;
                System.out.println(Thread.currentThread().getName() + 
                        "生产一件资源,当前资源池有" + num + "个");
                //唤醒等待的消费者
                consumerCondition.signalAll();
            }else{
                //让生产者线程等待
                try {
                    producerCondition.await();
                    System.out.println(Thread.currentThread().getName() + "线程进入等待");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }finally{
            lock.unlock();
        }
    }
    /**
     * 从资源池中取走资源
     */
    public void remove(){
        lock.lock();
        try{
            if(num > 0){
                num--;
                System.out.println("消费者" + Thread.currentThread().getName() 
                        + "消耗一件资源," + "当前资源池有" + num + "个");
                producerCondition.signalAll();//唤醒等待的生产者
            }else{
                try {
                    consumerCondition.await();
                    System.out.println(Thread.currentThread().getName() + "线程进入等待");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }//让消费者等待
            }
        }finally{
            lock.unlock();
        }
    }
    
}

BlockingQueue

package producerConsumer;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

//使用阻塞队列BlockingQueue解决生产者消费者
public class BlockingQueueConsumerProducer {
    public static void main(String[] args) {
        Resource3 resource = new Resource3();
        //生产者线程
        ProducerThread3 p = new ProducerThread3(resource);
        //多个消费者
        ConsumerThread3 c1 = new ConsumerThread3(resource);
        ConsumerThread3 c2 = new ConsumerThread3(resource);
        ConsumerThread3 c3 = new ConsumerThread3(resource);
 
        p.start();
        c1.start();
        c2.start();
        c3.start();
    }
}
/**
 * 消费者线程
 * @author tangzhijing
 *
 */
class ConsumerThread3 extends Thread {
    private Resource3 resource3;
 
    public ConsumerThread3(Resource3 resource) {
        this.resource3 = resource;
        //setName("消费者");
    }
 
    public void run() {
        while (true) {
            try {
                Thread.sleep((long) (1000 * Math.random()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            resource3.remove();
        }
    }
}
/**
 * 生产者线程
 * @author tangzhijing
 *
 */
class ProducerThread3 extends Thread{
    private Resource3 resource3;
    public ProducerThread3(Resource3 resource) {
        this.resource3 = resource;
        //setName("生产者");
    }
 
    public void run() {
        while (true) {
            try {
                Thread.sleep((long) (1000 * Math.random()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            resource3.add();
        }
    }
}
class Resource3{
    private BlockingQueue resourceQueue = new LinkedBlockingQueue(10);
    /**
     * 向资源池中添加资源
     */
    public void add(){
        try {
            resourceQueue.put(1);
            System.out.println("生产者" + Thread.currentThread().getName()
                    + "生产一件资源," + "当前资源池有" + resourceQueue.size() + 
                    "个资源");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * 向资源池中移除资源
     */
    public void remove(){
        try {
            resourceQueue.take();
            System.out.println("消费者" + Thread.currentThread().getName() + 
                    "消耗一件资源," + "当前资源池有" + resourceQueue.size() 
                    + "个资源");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

34、.xml中配置什么
监听器,过滤器,welcome-file,servlet,
35、实现线程安全的i++;
1、利用synchronize;
2、利用reentranlock;
3、利用reentranwriteandreadlock;
4、利用atomicinteger和count.incrementAndGet.
36、快速失败和安全失败
快速失败是利用迭代器时,如果有其他线程妄图修改集合类/map类就抛出快速失败
安全失败是拷贝一份

37 数组在内存的具体实现?内存角度分析?那么数组属于类吗?分析
int[] a=new int[100];
在堆中开辟一段100个int型的数据单元,a创建在栈区,a是这段内存的头指针。
但是数组不属于类,但是实现了类的所有方法。
38 计算机网络簇

39 jvm反射和cglicb反射怎么实现

40密码加密

41 保留登录状态有哪几种方法,项目里的实现?
保留登录状态就是要获取session,session的获取方法一共有三种
42 mysql优化和sql语句优化,以及mysql的debug工具?
mysql的优化从底层到顶:sql和索引优化,数据库表,系统配置,硬件
max,limit,group by,order by是sql语句优化
索引建立在 1 字段长度短2 离散程度大3 需要经常查询和排序的
过多的索引 不仅会影响写入效率,还会影响查询效率
表的建立:1选择最小的形式进行储存
2 尽量使用简单的形式,int比时间戳和char简单
3 尽量少使用not null
4 少用text

43 spring 的事务?
事务分为两种方式:一种是声明式,一种是编程式
声明式又分xml和注解
其中xml事务必须先实现txmanager和aop两种


<!-- 配置事务管理器 -->配置一个bean,类名是datasourcetransactionmanager,注入了DataSource

	<bean id="cityPickTransactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource_backend-product" />
		</property>
	</bean>
	 
<!-- 配置事务传播特性 -->注入上面的citypicktansactionmanager,然后对方法进行一个事务管理,记住事务管理的本质是在mysql操作的,即如果和数据库无关的就无需进行事务操作,但是几乎所有的后端的类都会和数据库发生交互,所以理论上都需要考虑数据库。一般对查的要求不高,所以使用support即可,如过要查的话,就使用required,可以用事务就用不用就算了。
	<tx:advice id="cityPickAdvice" transaction-manager="cityPickTransactionManager">
		<tx:attributes>
			<tx:method name="insert*" propagation="REQUIRED"
				rollback-for="Exception" />
			<tx:method name="add*" propagation="REQUIRED"
				rollback-for="Exception" />
			<tx:method name="create*" propagation="REQUIRED"
			           rollback-for="Exception" />
			<tx:method name="update*" propagation="NESTED"
				rollback-for="Exception" />
			<tx:method name="batchApply*" propagation="REQUIRED"
				rollback-for="Exception" />
			<tx:method name="save*" propagation="REQUIRED"
				rollback-for="Exception" />
			<tx:method name="delete*" propagation="REQUIRED"
				rollback-for="Exception" />
			<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
			<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
			<tx:method name="fetch*" propagation="SUPPORTS" read-only="true" />
			<tx:method name="is*" propagation="SUPPORTS" read-only="true" />
			<tx:method name="*_noTrans" propagation="NOT_SUPPORTED" />
			<tx:method name="*byTran" propagation="REQUIRED"/>
		</tx:attributes>
	</tx:advice>
<!-- 配置参与事务的类 -->
	<aop:config>
		<aop:pointcut id="cityPickManagerMethod"
			expression=" (
                            execution(* com.test.service.impl.CityPriceScheduleServiceImpl.*(..))
                         ) " />
		<aop:advisor advice-ref="cityPickAdvice" pointcut-ref="cityPickManagerMethod" />、、事务管理
	</aop:config>
 
</beans>

44 什么是hashcoede?hashcode的计算方法?为什么要重写equals时需要重写hashcode?
hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值。
31(31(31*h+v0)+v1)+v2… 迭乘
因为约定就是两个相等的对象就必须拥有相同的hashcode。因为假设在equals中没有重写hashcode,那么如果在hashmap中使用到这两个对象,因为hashmap是将两个相等的对象放在一个地方,而此时虽然对象A==B,但是没有重写hashcode,导致hashcode不等,从而导致将两个相等的对象放在两个不同的hashmap位置。
45 TCP和UDP的区别,TCP的报文结构,UDP的报文结构

46 http 的结构以及http1.0和http1.1,2.0区别

47 Linux下创建一个文件用什么命令,修改权限使用什么命令,修改所有者使用什么命令?查看网络连通?

48讲讲http协议,输入一个网址到浏览器呈现出界面的过程是什么样子的?

49https和http有什么区别,区别的细节是什么样子的?

50有哪些索引,它们底层是采用什么数据结构去实现的
51数据库同步你做过哪些方案,各有什么优缺点
52http的常用的状态有哪些,301和302的区别是什么,503是什么意思
200:请求被正常处理
204:请求被受理但没有资源可以返回
206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,相应报文中通过Content-Range指定范围的资源。
301:永久性重定向
302:临时重定向
303:与302状态码有相似功能,只是它希望客户端在请求一个URI的时候,能通过GET方法重定向到另一个URI上
304:发送附带条件的请求时,条件不满足时返回,与重定向无关
307:临时重定向,与302类似,只是强制要求使用POST方法
400:请求报文语法有误,服务器无法识别
401:请求需要认证
403:请求的对应资源禁止被访问
404:服务器无法找到对应资源
500:服务器内部错误
503:服务器正忙

53你们项目中上传图片是采用post的哪种方式
54百度的查询框中,假设你打了一个“中”,那么下面的一串的提示字符,类似“中国/中间”这些是如何出现的
55倒排索引的介绍
56Lucene的实现原理
57Linux中查看服务的命令
1、ps aux 或netstat -tlunp
ps是进程查看命令,netstat是端口查看命令,在Linux系统中,服务一定是有进程的,所以使用ps命令可以查看服务运行情况,另外,Linux服务多数是网络服务,所以通过netstat命令也可以查看服务运行状态。
2service 服务名 status
比如查看httpd的Web服务的运行状态,执行service httpd status,如下图所示:
3、/sbin/service --status-all |grep “服务名”
比如查看httpd的web服务,执行 /sbin/service --status-all |grep "httpd"即可。如下图所示。
4、chkconfig --list
比如查看httpd的web服务,执行 chkconfig --list |grep "httpd"即可。如下图所示。
58死锁的概念,导致死锁的原因。导致死锁的四个必要条件。处理死锁的四个方式。预防死锁的方法、避免死锁的方法。
1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放
2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
4.循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞
59 springboot的理解和使用?

60权限 RBAC

61.TreeMap如何保证有序,红黑树基本原理,红黑树存在的意义

62.hashmap线程不安全体现在什么方面?hashmap死循环产生的原因?

63.g1垃圾收集器的全称和原理,cms垃圾收集器的原理,串行垃圾收集器原理,并行垃圾收集器原理

64. 手写代码: 给一个任意树的节点序列,树的节点中包括了节点的值和他所有的孩子节点,请找出这棵树的父节点

66. volatile知道吗,底层怎么实现的?

67. java集合的几种接口,分别说说

68. 内存溢出以及如何解决,如何监控,内存泄漏呢?
1 内存溢出是指超过了规定内存的大小
2 内存泄漏是指没有及时回收内存,导致最后无可用内存,最后内存溢出
内存溢出的产生条件
1 递归,递归算法由于一直需要引用上一层的对象,对象不能被及时的gc,最后内存溢出。循环也会产生类似的情况,相对来说递归更加危险。
2 启动内存设置过小,在jvm虚拟机可以设置。包括堆区以及栈区。
3 硬件内存过小
内存泄漏的产生条件
1 连接未关闭,io流或者线程之类的
2 监听器未关闭
3 大量的一次性String,如果可以使用stringbuffer
4 静态集合类,使用完置null
监控
Jprofiler
visualvm
69. 集合遍历的时候进行修改如何解决

70 如何进行对象的拷贝

71、线程如何实现同步和共享?
同步概念和异步是相对的 synchronize是实现同步的最简单的方法
共享的本质是
72 struts2的总体架构及流程?

73 线程和进程
线程是共享内存的,而进程是拥有独立的内存区域
线程是cpu执行的最小单位,而进程是线程的集合
线程是轻量级的,而进程是重量级的。

75单例模式的注意点 volatile和synchronized构造单例
饿汉式(线程安全,但是费内存)

public class Singleton_E {
	private  Singleton_E() {
		// TODO Auto-generated constructor stub
	}
	private static Singleton_E e=new Singleton_E();
	public static Singleton_E getsingleton() {
		return e;
		
	}
}

懒汉式(有判断null所以不安全,所以不可用多线程)

public class Singleton_E {
	private Singleton_E() {
		// TODO Auto-generated constructor stub
	}

	private static Singleton_E e = null;

	public static Singleton_E getsingleton() {
		if (e == null) {
			e=new Singleton_E();
		}
		return e;

	}
}

**线程安全:**懒汉式
final

public class Singleton_E {
	private Singleton_E() {
		// TODO Auto-generated constructor stub
	}

	private static Singleton_Einstance {
	private static final Singleton_E E=new Singleton_E();
	}

	public static Singleton_E getsingleton() {
		return Singleton_Einstance.Singleton_E;

	}
}

volatile+synchronize(代码块级)

public class Singleton_E {
	private Singleton_E() {
		// TODO Auto-generated constructor stub
	}

	private volatile static Singleton_E e = null;

	public static Singleton_E getsingleton() {
		if (e == null) {
			synchronized(Singleton_E.class)
			if(e==null){
				e=new Singleton_E();
				}
		}
		return e;

	}
}

synchronize 方法级

public class Singleton_E {
	private Singleton_E() {
		// TODO Auto-generated constructor stub
	}

	private static Singleton_E e = null;

	public synchronized static Singleton_E getsingleton() {
		if (e == null) {
			e=new Singleton_E();
		}
		return e;

	}
}

枚举

76 hashMap存取的操作,如何解决哈希冲突,modCount是干啥的,先插入元素还是先扩容,扩容时大量元素位置失效,如何进行元素迁移

77长连接短连接,在请求头响应头里面时如何体现的

78redis 数据类型,如果要你做一个排序的功能,需要用redis哪个类型

79redis单机能存放多少数据

80数据库索引是什么原理

81 B和B+树说一下区别,和二叉树啥区别

82什么时候索引失效
使用函数
前一个有索引后一个没有

83你项目里面有数据库优化的内容,怎么优化的

84讲一下一致性哈希,里面什么哈希函数

85你用过的哈希函数,有什么区别

猜你喜欢

转载自blog.csdn.net/zhunquanjiong6199/article/details/83112087