递归方法:javascript
public Node reverse(Node head) { if (head == null || head.next == null) return head; Node temp = head.next; Node newHead = reverse(head.next); temp.next = head; head.next = null; return newHead; } //整体来讲,递归法是从最后一个Node开始,在弹栈的过程当中将指针顺序置换的。
遍历方法:css
public static Node reverseList(Node node) { Node pre = null; Node next = null; while (node != null) { next = node.next; node.next = pre; pre = node; node = next; } return pre; } //先将下一节点纪录下来,而后让当前节点指向上一节点,再将当前节点纪录下来,再让下一节点变为当前节点。
Java线程池详解java
一、什么是死锁:死锁是指多个进程因竞争资源而形成的一种僵局(互相等待),若无外力做用,这些进程都将没法向前推动。node
二、死锁的四个必要条件:redis
互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所占有,此时如有其余进程请求该资源,则请求进程只能等待;算法
请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其余进程占有,此时请求进程被阻塞,但对本身已得到的资源保持不放;数据库
不可剥夺条件:进程所得到的资源在未使用完毕以前,不能被其余进程强行夺走,即只能由得到该资源的进程本身来释放(只能主动释放);bootstrap
循环等待条件:若干进程间造成首尾相接循环等待资源的关系;segmentfault
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不知足,就不会发生死锁。
三、死锁的避免:指定获取锁和释放锁的顺序。
四、死锁的预防:破坏致使死锁的必要条件,使其不被知足。
四、Http1.0,Http1.1,Http2.0主要特性对比
五、http和https的区别:
(1)https协议须要到ca申请证书,通常免费证书较少,于是须要必定费用;
(2)http是超文本传输协议,信息是明文传输,https则是具备安全性的ssl加密传输协议;
(3)http和https使用的端口不一样,前者是80,后者是443;
(4)http的链接很简单,是无状态的;https协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
一、内存溢出:
是指程序在申请内存时,没有足够的内存空间供其使用,出现内存溢出,好比申请了一个integer,但给它存了long才能存下的数,那就是内存溢出;内存溢出就是你要求分配的内存超出了系统能给你的,系统不能知足需求,因而产生溢出。
二、内存泄漏:
是指程序在申请内存后,没法释放已申请的内存空间,一次内存泄漏危害能够忽略,但内存泄漏堆积后果很严重,不管多少内存,早晚会被占光,内存泄漏最终会致使内存溢出。内存泄漏是指你向系统申请分配内存进行使用,但是使用完了之后却不归还,结果你申请到的那块内存你本身也不能再访问,而系统也不能再次将它分配给须要的程序。
三、内存泄漏如何产生:
Java内存泄漏的根本缘由是长生命周期的对象持有短生命周期对象的引用就极可能发生内存泄漏,尽管短生命周期对象已经再也不须要,可是由于长生命周期持有它的引用而致使不能被回收,这就是Java中内存泄漏的发生场景。
HashMap基于哈希思想,实现对数据的读写,底层采用数组+链表实现,能够存储null键和null值,线程不安全:
一、同步:
同步就是发起一个请求,直到请求返回结果以后,才进行下一步操做;简单来讲,同步就是必须一件事一件事的作,等前一件作完了,才能作下一件事。
二、异步:
异步很明显是与同步相对,两者的区别在因而否须要等待某操做的返回结果;简单来讲,咱们仍是一个网络请求,若是咱们此时不须要依赖这个请求的结果就能进行后续操做,那么此时这个网络请求就是一个异步操做。
三、同步阻塞:
效率最低,专心等待事情完成,什么别的事都不作。
四、异步阻塞:
异步操做是能够被阻塞的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻塞。
五、同步非阻塞:
其实是效率低下的,一边干别的事情一边还须要抬头看上一件事完成没有,若是把干别的事情和观察完成状况当作是程序的两个操做的话,这个程序须要在这两种不一样的行为之间来回的切换,效率可想而知是低下的。
六、异步非阻塞:
效率更高,由于等待事情完成是等待者的事,而通知你则是消息触发机制的事,程序没有在这两种不一样的操做中来回切换。
一、简介:
装饰者模式经过组合的方式扩展对象的特性,这种方式容许咱们在任什么时候候对对象的功能进行扩展甚至是运行时扩展,若咱们用继承来完成对类的扩展则只能在编译阶段实现,因此在某些时候装饰者模式比继承要更加灵活。
二、装饰者模式在jdk中的使用场景:
java.io包(BufferInputStream至关于一个装饰器实现者,使得FilterInputStream读取的数据能暂存在内存中,从减小I/O的角度提升了读取效率)。
三、装饰者模式简单的业务使用场景:
咖啡店里的咖啡加上不一样的配料(牛奶、糖、奶泡)有不一样的价钱,可使用装饰者模式实现;首先定义一个咖啡基类,接着定义一个装饰器类继承咖啡基类,最后来实现添加配料的装饰子类。
一、手写单例模式实现:
//饿汉式 public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance(){ return instance; } } //懒汉式 public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance(){ if (instance == null) { instance = new Singleton(); } return instance; } }
首先单例类必需要有一个private访问级别的构造函数,只有这样,才能确保单例不会在系统中的其余代码内被实例化,这点是至关重要的;其次,singleton成员和getSingleton()方法必须是static的。
二、多线程中的懒汉式单例模式(synchronized方法级别锁):
public class Singleton { private static Singleton instance;
private Singleton() { } public static synchronized Singleton getInstance(){ if (instance == null) { instance = new Singleton(); } return instance; } }
三、双重锁实现的单例模式:
public class Singleton { private volatile static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
双重加锁要对instance域加上volatile修饰符,synchronized并非对instance实例进行加锁(由于如今还并无实例),因此线程在执行完instance = new Singleton()后,instance的值被修改,应该将修改后的instance当即写入主存,而不是暂时存在寄存器或者高速缓冲区中,以保证新的值对其它线程可见。
四、静态内部类实现的单例模式:
public class SingleTon{ private SingleTon(){ } private static class SingleTonHoler{ private static SingleTon instance = new SingleTon(); } public static SingleTon getInstance(){ return SingleTonHoler.instance; } }
外部类加载时并不须要当即加载内部类,内部类不被加载则不去初始化instance,故而不占内存,即当SingleTon第一次被加载时,并不须要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,才会去初始化instance,第一次调用getInstance()方法会致使虚拟机加载SingleTonHoler类,这种方法不只能确保线程安全,也能保证单例的惟一性,同时也延迟了单例的实例化。
一、redis实现分布式锁:
使用redis命令 set key value NX EX max-lock-time 实现加锁
使用redis命令 EVAL 实现解锁
二、redis的两种持久化方式:
一、储存引擎选择,若是数据表须要事务处理,应该考虑使用InnoDB, 由于它完成兼容ACID特性(即事务的四大特性),若是不须要事务处理,使用默认储存引擎MyISAM。
二、对查询进行优化,尽可能避免全表扫描,能够考虑在where及order by涉及的列上创建索引。
三、应尽可能避免在where子句中对字段进行null值判断,不然将导则引擎放弃使用索引而进行全表扫描。
四、对于多张大数据量表的JOIN,要先分页再JOIN,不然逻辑读会很高,性能差。
一、SSL:
SSL(安全套接层)是TCP/IP协议中基于HTTP之下TCP之上的一个可选协议层;起初HTTP在传输数据时使用的是明文,是不安全的,为了解决这个隐患,网景公司推出了SSL,愈来愈多的人也开始使用HTTPS(HTTP+SSL)。
二、TLS:
SSL更新到3.0时,互联网工程任务组将其改名为TLS1.0(安全传输层协议),TLS也就是SSL的新版本3.1。
三、区别:
(1)SSL与TLS二者所使用的算法是不一样的
(2)TLS增长了许多新的报警代码,好比解密失败、拒绝访问等,但同时也支持SSL协议上全部的报警代码
一、TCP:可靠、面向链接、面向字节流、传输效率低
二、UDP:不可靠、无链接、面向报文、传输效率高
三、TCP应用场景:
当对网络通讯质量要求高的时候,好比整个数据要准确无误的传递给对方,这时就使用TCP,好比浏览器使用的HHTP协议、QQ文件传输。
四、UDP应用场景:
当对网络通信质量要求不高的时候,要求网络通信速度尽可能的快,这时就使用UDP,好比QQ语音、QQ视频。
管道、消息队列、信号量、共享内存。
线程上下文、共享内存、Socket套接字(不一样的机器之间进行通讯)。
Redis是内存数据库,数据保存在内存中,访问速度快;
MySQL是关系型数据库,功能强大,存储在磁盘中,数据访问速度慢。
一、MySQL只有Innodb引擎支持数据库的事务操做,事务是一条或多条数据库操做的集合,在事务中的操做,要么都执行修改,要么都不执行,MySQL事务具备原子性、一致性、隔离性、持久性(ACID)。
二、事务的隔离级别:
未提交读:事务中的修改,即便没有提交,在其余事务也都是可见的;事务能够读取未提交的数据,这也被称为脏读。
提交读:一个事务从开始直到提交以前,所作的任何修改对其余事务都是不可见的;这个级别有时候也叫作不可重复读,由于两次执行相同的查询,可能会获得不同的结果,由于在这两次读之间可能有其余事务更改这个数据,每次读到的数据都是已经提交的。
可重复读:解决了脏读,也保证了在同一个事务中屡次读取一样记录的结果是一致的;可重复读隔离级别仍是没法解决另一个幻读的问题,指的是当某个事务在读取某个范围内的记录时,另一个事务也在该范围内插入了新的记录,当以前的事务再次读取该范围内的记录时,会产生幻行。
可串行化:经过强制事务串行执行,避免了前面说的幻读的问题,但因为读取的每行数据都加锁,会致使大量的锁征用问题,所以性能也最差。
经过哈希算法,将40亿个qq号按照哈希值散落到多个文件中,重复的qq号有相同的哈希值,确定位于一个文件中,这样就能够分别对每一个文件排序删除重复的qq号。
DNS域名解析 –>
发起TCP的三次握手 –>
创建TCP链接后发起http请求 –>
服务器响应http请求,浏览器获得html代码 –>
浏览器解析html代码,并请求html代码中的资源(如javascript、css、图片等) –>
浏览器对页面进行渲染呈现给用户。
(1)cookie经过在客户端记录信息肯定用户身份,session经过在服务器端记录信息肯定用户身份;
(2)cookie数据存放在客户的浏览器上,session数据存放在服务器上;
(3)cookie不是很安全,他人能够分析存放在本地的cookie进行cookie欺骗,而session较为安全,考虑安全问题应当使用session;
(4)session会在必定时间内保存在服务器上,当服务器的访问量增多时,会占用服务器的内存,考虑减轻服务器负载的问题,应该使用cookie;
cpu平均负载是指某段时间内占用cpu时间的进程和等待cpu时间的进程数,这里等待cpu时间的进程是指等待被唤醒的进程,不包括处于wait状态进程。
在命令窗口中输入 ipconfig 便可查看。
第一次握手:客户端发送一个带SYN的报文到服务器端,表示客户端想要和服务器端创建链接;
第二次握手:服务器端接收到客户端的请求,返回客户端报文,这个报文带有SYN和ACK确认标识;
第三次握手:客户端再次响应服务端一个ACK确认,表示已经准备好了。
第一次挥手:客户端发送一个FIN,关闭客户端到服务器端的链接;
第二次挥手:服务器端收到这个FIN后发回一个ACK确认标识,确认收到;
第三次挥手:服务器端发送一个FIN到客户端,服务器端关闭客户端的链接;
第四次挥手:客户端发送ACK报文确认,这样关闭完成。
类加载过程包括加载、验证、准备、解析和初始化五个阶段。
一、java类加载器的种类:
引导类加载器(bootstrap classloader);
扩展类加载器(extensions classloader);
应用程序类加载器(application classloader);
自定义类加载器(java.lang.classloder)。
二、类加载器之间的关系:
启动类加载器,由C++实现,没有父类;
拓展类加载器,由Java语言实现,父类加载器为null;
系统类加载器,由Java语言实现,父类加载器为拓展类加载器;
自定义类加载器,父类加载器确定为系统类加载器。
三、双亲委派机制工做原理:
若是一个类加载器收到了类加载请求,它并不会本身先去加载,而是把这个请求委托给父类的加载器去执行,若是父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,若是父类加载器能够完成类加载任务,就成功返回,假若父类加载器没法完成此加载任务,子加载器才会尝试本身去加载,这就是双亲委派模式,即每一个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子本身想办法去完成。
四、双亲委派机制的做用:
经过这种层级关能够避免类的重复加载,当父亲已经加载了该类时,就没有必要让子类加载器再加载一次;其次是考虑到安全因素,java核心api中定义的类型不会被随意替换。
第一次建立Session的时候,服务端会在HTTP协议中告诉客户端,须要在 Cookie 里面记录一个Session ID,之后每次请求把这个会话ID发送到服务器,就能知道是哪一个用户了。
在某段时间内,对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏,这种状况就称为拥塞,简单的说拥塞产生的缘由有两点:接收方容量不够、网络内部有瓶颈。
TCP进行拥塞控制的四种算法:慢启动、拥塞避免、快速重传、快速恢复。