这么经典全面的java岗面试题不了解下?

Java面试的一些题目,个人觉得很经典转过来了,答案准备自己找,保证质量所以贴个原创不断更新,当然也可以去原文找。


题目区

Java基础:

面向对象和面向过程的区别

Java的四个基本特性(抽象、封装、继承,多态)

Overload和Override的区别

构造器Constructor是否可被override

访问控制符public,protected,private,以及默认的区别

是否可以继承String类

String和StringBuffer、StringBuilder的区别

hashCode和equals方法的关系

抽象类和接口的区别

自动装箱与拆箱

什么是泛型、为什么要使用以及泛型擦除

Java中的集合类及关系图

HashMap实现原理(看源代码)

HashTable实现原理(看源代码)

HashMap和HashTable区别

HashTable如何实现线程安全(看源代码)

ArrayList和vector区别(看源代码)

ArrayList和LinkedList区别及使用场景

Collection和Collections的区别

Concurrenthashmap实现原理(看源代码)

Error、Exception区别

Unchecked Exception和Checked Exception,各列举几个

Java中如何实现代理机制(JDK、CGLIB)

多线程的实现方式

线程的状态转换

如何停止一个线程

什么是线程安全

如何保证线程安全

Synchronized如何使用

synchronized和Lock的区别

多线程如何进行信息交互

sleep和wait的区别(考察的方向是是否会释放锁)

多线程与死锁

如何才能产生死锁

什么叫守护线程,用什么方法实现守护线程

Java线程池技术及原理

java并发包concurrent及常用的类

volatile关键字

Java中的NIO,BIO,AIO分别是什么

IO和NIO区别

序列化与反序列化

常见的序列化协议有哪些

内存溢出和内存泄漏的区别

Java内存模型及各个区域的OOM,如何重现OOM

出现OOM如何解决

用什么工具可以查出内存泄漏

Java内存管理及回收算法

Java类加载器及如何加载类(双亲委派)

xml解析方式

Statement和PreparedStatement之间的区别

JavaEE:

servlet生命周期及各个方法

servlet中如何自定义filter

JSP原理

JSP和Servlet的区别

JSP的动态include和静态include

Struts中请求处理过程

MVC概念

Spring mvc与Struts区别

Hibernate/Ibatis两者的区别

Hibernate一级和二级缓存

Hibernate实现集群部署

Hibernate如何实现声明式事务

简述Hibernate常见优化策略

Spring bean的加载过程(推荐看Spring的源码)

Spring如何实现AOP和IOC

Spring bean注入方式

Spring的事务管理(推荐看Spring的源码)

Spring事务的传播特性

springmvc原理

springmvc用过哪些注解

Restful有几种请求

Restful好处

Tomcat,Apache,JBoss的区别

memcached和redis的区别

有没有遇到中文乱码问题,如何解决的

如何理解分布式锁

你知道的开源协议有哪些

json和xml区别

设计模式:

设计模式的六大原则

常用的设计模式

用一个设计模式写一段代码或画出一个设计模式的UML

如何理解MVC

高内聚,低耦合方面的理解

算法:

深度优先、广度优先算法

排序算法及对应的时间复杂度和空间复杂度

写一个排序算法

查找算法

B+树和二叉树查找时间复杂度

KMP算法、hash算法

常用的hash算法有哪些

如何判断一个单链表是否有环?

给你一万个数,如何找出里面所有重复的数?用所有你能想到的方法,时间复杂度和空间复杂度分别是多少?

给你一个数组,如何里面找到和为K的两个数?

100000个数找出最小或最大的10个?

一堆数字里面继续去重,要怎么处理?

数据结构:

队列、栈、链表、树、堆、图

编码实现队列、栈

Linux:

linux常用命令

如何查看内存使用情况

Linux下如何进行进程调度

操作系统:

操作系统什么情况下会死锁

产生死锁的必要条件

死锁预防

数据库:

范式

数据库事务隔离级别

数据库连接池的原理

乐观锁和悲观锁

如何实现不同数据库的数据查询分页

SQL注入的原理,如何预防

数据库索引的实现(B+树介绍、和B树、R树区别)

SQL性能优化

数据库索引的优缺点以及什么时候数据库索引失效

Redis的存储结构

网络:

OSI七层模型以及TCP/IP四层模型

HTTP和HTTPS区别

HTTP报文内容

get提交和post提交的区别

get提交是否有字节限制,如果有是在哪限制的

TCP的三次握手和四次挥手

session和cookie的区别

HTTP请求中Session实现原理

redirect与forward区别

DNS

TCP和UDP区别

安全:

如果客户端不断的发送请求连接会怎样

DDos攻击

DDos预防


答案区
面向对象和面向过程的区别
资料

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用分别的函数来实现,问题就解决了。
而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为
1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的i变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。
可以明显地看出,面向对象是以功能来划分问题,而不是步骤。同样是绘制棋局,这样的行为在面向过程的设计中分散在了总多步骤中,很可能出现不同的绘制版本,因为通常设计人员会考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一。
功能上的统一保证了面向对象设计的可扩展性。比如我要加入悔棋的功能,如果要改动面向过程的设计,那么从输入到判断到显示这一连串的步骤都要改动,甚至步骤之间的循序都要进行大规模调整。如果是面向对象的话,只用改动棋盘对象就行了,棋盘系统保存了黑白双方的棋谱,简单回溯就可以了,而显示和规则判断则不用顾及,同时整个对对象功能的调用顺序都没有变化,改动只是局部的。
再比如我要把这个五子棋游戏改为围棋游戏,如果你是面向过程设计,那么五子棋的规则就分布在了你的程序的每一个角落,要改动还不如重写。但是如果你当初就是面向对象的设计,那么你只用改动规则对象就可以了,五子棋和围棋的区别不就是规则吗?(当然棋盘大小好像也不一样,但是你会觉得这是一个难题吗?直接在棋盘对象中进行一番小改动就可以了。)而下棋的大致步骤从面向对象的角度来看没有任何变化。
当然,要达到改动只是局部的需要设计的人有足够的经验,使用对象不能保证你的程序就是面向对象,初学者或者很蹩脚的程序员很可能以面向对象之虚而行面向过程之实,这样设计出来的所谓面向对象的程序很难有良好的可移植性和可扩展性。

Java的四个基本特性(抽象、封装、继承,多态)
资料

一.封装

封装:把对象的属性和方法结合成一个独立的整体,隐藏实现细节,并提供对外访问的接口。

封装的优点:

1.隐藏实现细节。

2.安全性。

比如你在程序中私有化了age属性,并提供了对外的get和set方法,当外界 使用set方 方法为属性设值的时候 ,你可以在set方法里面做个if判断,把值设值在0-80岁,那样他就不能随意赋值了。
3.增加代码复用性。比如在工具中封装的各种方法,可以任意调用,而不用每处去实现细节。
4。模块化。
封装分为封装属性,方法,类等等。有利于代码调试,相互配合。
二.继承
继承的概念:从已知的一个类中派生出一个新的类,叫子类。子类实现了父类所有非私有化的属性和方法,并根据实际需求扩展出新的行为。

继承的好处:

1.继承是传递的,易于在其基础上构造和扩充。

2.简化对事物的描绘,使得层次更加清晰。

3.减少代码冗余。

4.提高可维护性。

三.多态

多态的概念:多个不同的对象对同一消息作出响应。同一消息根据不同的对象而采用各种不同的方法。

多态的好处:主要是利于扩展。
四。抽象与接口
抽象的概念:通过特定的实例抽取出共同的特征行成概念的过程。
抽象方法:

被abstract修饰的方法是抽象方法。抽象方法没有方法体。修饰符返回类型为 函数名();抽象方法的修饰只能用public或protected或者没有修饰。不能被final,static,private修饰。

抽象与接口的区别:

不同:

1.接口可以多实现,而抽象类只能单继承。

2.抽象类可以具有非抽向的方法和构造方法,变量。但是接口只有抽象方法,静态常量。

3.抽象类和子类有父子关系,子类能拥有弗雷德一些属性。接口虽然某个类实现一个接口,但由于接口中的变量都为静态常量,不存在继承关系。

相同点:

1.无论接口还是抽象类,都无法被直接实例化,其自身实例化需要靠实现类或者子类实现。

Overload和Override的区别
资料

Override是重写:
方法名称、参数个数,类型,顺序,返回值类型都是必须和父类方法一致的。它的关系是父子关系,
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
Overload是重载:方法名称不变,其余的都是可以变更的。它的关系是同一个类,同一个方法名,不同的方法参数或返回值。
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
备注:它们都是是Java多态性的不同表现

构造器Constructor是否可被override

构造器是用来生成一个类的实例是用来初始化这个实例用的,构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。Constructor不能被继承,所以Constructor也就不能被override。每一个类必须有自己的构造函数,负责构造自己这部分的构造。子类不会覆盖父类的构造函数,相反必须负责在一开始调用父类的构造函数。
总之:构造器不是方法,那么用来修饰方法特性的所有修饰符都不能用来修饰构造器(并不等与构造器具备这些特性,虽然不能用static修饰构造器,但它却有静态特性)构造器只能用 public private protected这三个权限修饰符,且不能有返回语句。

访问控制符public,protected,private,以及默认的区别
资料
这里写图片描述

类的成员不写访问修饰符默认为default,默认对于同一个包的其他类相当于公开(public),对于不是同一个包的其他类相当于私有(private)。受保护(protected)对子类相当于公开,对于不是同一个包没有父子关系的类相当于私有。Java中,外部类的修饰符只能是public或默认,类的成员(包括内部类)的修饰符可以是以上四种。

是否可以继承String类
不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变。
String和StringBuffer、StringBuilder的区别
资料

首先 `StringBuffer和StringBuilder都继承自AbstractStringBuilder这个类,而AbstractStringBuilder和String都继承自超类Object。
1、执行速度:
StringBuilder > StringBuffer > String
String最慢的原因:
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
2. 线程安全
StringBuilder是线程不安全的,而StringBuffer是线程安全的。两者有相同的方法,除了StringBuilders所有方法同步,以及其对象是可以修改的字符串。
3. 总结
  String:适用于少量的字符串操作的情况
  StringBuilder:适用於单线程下在字符缓冲区进行大量操作的情况
  StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

hashCode和equals方法的关系
资料

1.hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用。
2.equals和hashCode需要同时覆盖。
3.若两个对象equals返回true,则hashCode有必要也返回相同的int数。
4.若两个对象equals返回false,则hashCode不一定返回不同的int数,但为不相等的

对象生成不同hashCode值可以提高哈希表的性能。
5.若两个对象hashCode返回相同int数,则equals不一定返回true。
6.若两个对象hashCode返回不同int数,则equals一定返回false。
7.同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。

抽象类和接口的区别
资料

抽象类是用来捕捉子类的通用特性的 。它不能被实例化,只能被用作子类的超类。抽象类是被用来创建继承层级里子类的模板。 接口是抽象方法的集合。

这里写图片描述

什么时候使用抽象类和接口?
如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。

自动装箱与拆箱

自动装箱:
Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象;
因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱。

什么是泛型、为什么要使用以及泛型擦除
资料

泛型:本质是参数化类型。
为什么要使用?
创建集合的时候,往集合里面添加数据,再次取出时,集合会忘记这数据类型,该对象的编译类型就会变成Object类型,否则如果想要变回原来的数据类型的时候,就要强制进行转换。创建集合的时候,我们就指定集合类型,避免这个过程。
泛型擦除?
Java的泛型处理过程都是在编译器中进行的,编译器首先会生成bytecode码,这个过程是不包括泛型类型,泛型类型在编译的时候是被擦除的,这个过程及泛型擦除。
泛型擦除的过程: 1将所有泛型参数用顶级父类类型替换 2擦除所有的参数类型

Java中的集合类及关系图(没理解什么意思)
资料

List和Set继承自Collection接口。 Set无序不允许元素重复。HashSet和TreeSet是两个主要的实现类。
List有序且允许元素重复。ArrayList、LinkedList和Vector是三个主要的实现类。
Map也属于集合系统,但和Collection接口没关系。Map是key对value的映射集合,其中key列就是一个集合。key不能重复,但是value可以重复。
HashMap、TreeMap和Hashtable是三个主要的实现类。SortedSet和SortedMap接口对元素按指定规则排序,SortedMap是对key列进行排序。

HashMap实现原理
资料

HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用LinkedList来解决碰撞问题,当发生碰撞了,对象将会储存在LinkedList的下一个节点中。 HashMap在每个LinkedList节点中储存键值对对象。当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的LinkedList中。键对象的equals()方法用来找到键值对。
多线程环境下,使用Hashmap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap。

HashTable实现原理

不理解待填

HashMap和HashTable区别
资料(附带HashSet和HashMap、Hashtable的区别)

1、两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全
Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,我们平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说就是Collections.synchronizedMap()方法帮我们在操作HashMap时自动添加了synchronized来实现线程同步,类似的其它Collections.synchronizedXX方法也是类似原理)
2、HashMap可以使用null作为key,而Hashtable则不允许null作为key
虽说HashMap支持null值作为key,不过建议还是尽量避免这样使用,因为一旦不小心使用了,若因此引发一些问题,排查起来很是费事
HashMap以null作为key时,总是存储在table数组的第一个节点上
3、HashMap是对Map接口的实现,HashTable实现了Map接口和Dictionary抽象类
4、HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75
HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1
5、两者计算hash的方法不同,Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模

HashTable如何实现线程安全
资料

线程安全就是多线程访问时(WEB网页多用户访问一个页面时),采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
其实现方式是在对应的方法上加上synchronized关键字,不过效率不高。

ArrayList和vector区别
资料

ArrayList和 Vector都实现了List接口, 都是通过数组实现的。
Vector是线程安全的,而ArrayList是非线程安全的。
Vector类中的方法是同步的,而ArrayList中的方法不同步。
ArrayList类仅适用于对象,不适用于原始数据类型。要使用要使用原始数据类型需要先申请一个包装类,如ArraList <integer>
List第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当 List 认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。

ArrayList和LinkedList区别及使用场景
资料

ArrayList底层是用数组实现的,可以认为ArrayList是一个可改变大小的数组。随着越来越多的元素被添加到ArrayList中,其规模是动态增加的。
LinkedList底层是通过双向链表实现的, LinkedList和ArrayList相比,增删的速度较快。但是查询和修改值的速度较慢。同时,LinkedList还实现了Queue接口,所以他还提供了offer(), peek(), poll()等方法。
LinkedList更适合从中间插入或者删除(链表的特性)。 ArrayList更适合检索和在末尾插入或删除(数组的特性)

Collection和Collections的区别
资料

java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
java.util.Collections是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

Concurrenthashmap实现原理
资料
Error、Exception区别
资料

首先,Error类和Exception类都是继承Throwable类
Error(错误)是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序才能修正。一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
Exception又分为两类
CheckedException:(编译时异常) 需要用try——catch显示的捕获,对于可恢复的异常使用CheckedException。
UnCheckedException(RuntimeException):(运行时异常)不需要捕获,对于程序错误(不可恢复)的异常使用RuntimeException。Error和Exception就像是水池和水池里的水的区别
“水池”,就是代码正常运行的外部环境,如果水池崩溃(系统崩溃),或者池水溢出(内存溢出)等,这些都是跟水池外部环境有关。这些就是java中的error
“水池里的水”,就是正常运行的代码,水污染了、有杂质了,浑浊了,这些影响水质的因素就是Exception。

Unchecked Exception和Checked Exception,各列举几个
资料

Unchecked Exception: a. 指的是程序的瑕疵或逻辑错误,并且在运行时无法恢复。 b.
包括Error与RuntimeException及其子类,如:OutOfMemoryError,
UndeclaredThrowableException, IllegalArgumentException,
IllegalMonitorStateException, NullPointerException,
IllegalStateException, IndexOutOfBoundsException等。 c. 语法上不需要声明抛出异常。

Checked Exception: a. 代表程序不能直接控制的无效外界情况(如用户输入,数据库问题,网络异常,文件丢失等) b.
除了Error和RuntimeException及其子类之外,如:ClassNotFoundException,
NamingException, ServletException, SQLException, IOException等。 c.
需要try catch处理或throws声明抛出异常。

Java中如何实现代理机制(JDK、CGLIB)
资料

什么是代理模式呢?代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。
按照代理的创建时期,一般分为两类:
静态代理:由程序员或特定工具自动生成的源代码,再对其编译,在程序运行之前,代理的类编译生成的.class文件就已经存在了
动态代理:在程序运行时,通过反射机制动态创建而成。
JDK动态代理:代理类和目标类实现了共同的接口,用到InvocationHandler接口。
CGLIB动态代理:代理类是目标类的子类, 用到MethodInterceptor接口

多线程的实现方式
资料

Java多线程实现方式主要有四种:继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。
其中前两种方式线程执行完后都没有返回值,后两种是带返回值的。
1、继承Thread类创建线程
Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
2、实现Runnable接口创建线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,可以实现一个Runnable接口。

线程的状态转换
资料
这里写图片描述

线程状态类型
新建状态(New):新创建了一个线程对象。
就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

如何停止一个线程
资料
在java中有以下3种方法可以终止正在运行的线程:
- 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
- 使用stop方法强行终止,但是不推荐这个方法,因为stop和suspend及resume一样都是过期作废的方法。(不安全
- 使用interrupt方法中断线程。

什么是线程安全

线程安全就是多线程访问时(WEB网页多用户访问一个页面时),采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

如何保证线程安全
资料

一般说来,确保线程安全的方法有这几个:竞争与原子操作、同步与锁、可重入、过度优化
1. 竞争与原子操作
多个线程同时访问和修改一个数据,可能造成很严重的后果。出现严重后果的原因是很多操作被操作系统编译为汇编代码之后不止一条指令,因此在执行的时候可能执行了一半就被调度系统打断了而去执行别的代码了。一般将单指令的操作称为原子的(Atomic),因为不管怎样,单条指令的执行是不会被打断的。
因此,为了避免出现多线程操作数据的出现异常,Linux系统提供了一些常用操作的原子指令,确保了线程的安全。但是,它们只适用于比较简单的场合,在复杂的情况下就要选用其他的方法了。
2. 同步与锁
为了避免多个线程同时读写一个数据而产生不可预料的后果,开发人员要将各个线程对同一个数据的访问同步,也就是说,在一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问。
同步的最常用的方法是使用锁(Lock),它是一种非强制机制,每个线程在访问数据或资源之前首先试图获取锁,并在访问结束之后释放锁;在锁已经被占用的时候试图获取锁时,线程会等待,直到锁重新可用。
二元信号量是最简单的一种锁,它只有两种状态:占用与非占用,它适合只能被唯一一个线程独占访问的资源。对于允许多个线程并发访问的资源,要使用多元信号量(简称信号量)。
3. 可重入
一个函数被重入,表示这个函数没有执行完成,但由于外部因素或内部因素,又一次进入该函数执行。一个函数称为可重入的,表明该函数被重入之后不会产生任何不良后果。可重入是并发安全的强力保障,一个可重入的函数可以在多线程环境下放心使用。
4. 过度优化
在很多情况下,即使我们合理地使用了锁,也不一定能够保证线程安全,因此,我们可能对代码进行过度的优化以确保线程安全。

Synchronized如何使用
资料

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
一. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
二. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
三. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
四. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

synchronized和Lock的区别
资料

主要相同点:Lock能完成synchronized所实现的所有功能
主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。Lock的锁定是通过代码实现的,而synchronized是在JVM层面上实现的,synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。Lock锁的范围有局限性,块范围,而synchronized可以锁住块、对象、类。

多线程如何进行信息交互
资料

void notify() 唤醒在此对象监视器上等待的单个线程。 void notifyAll() 唤醒在此对象监视器上等待的所有线程。
void wait() 导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。 void
wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量。 void
wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。

sleep和wait的区别(考察的方向是是否会释放锁)
资料

sleep()方法是Thread类中方法,而wait()方法是Object类中的方法。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态,在调用sleep()方法的过程中,线程不会释放对象锁。而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备

多线程与死锁
资料

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。 产生死锁的原因:
一.因为系统资源不足。 二.进程运行推进的顺序不合适。 三.资源分配不当。

如何才能产生死锁
资料

产生死锁的四个必要条件: 一.互斥条件:所谓互斥就是进程在某一时间内独占资源。
二.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 三.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
四.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

什么叫守护线程,用什么方法实现守护线程
资料

守护线程是为其他线程的运行提供服务的线程。 setDaemon(boolean
on)方法可以方便的设置线程的Daemon模式,true为守护模式,false为用户模式。

Java线程池技术及原理

java并发包concurrent及常用的类

volatile关键字

Java中的NIO,BIO,AIO分别是什么

IO和NIO区别

序列化与反序列化

常见的序列化协议有哪些

内存溢出和内存泄漏的区别

Java内存模型及各个区域的OOM,如何重现OOM

出现OOM如何解决

用什么工具可以查出内存泄漏

Java内存管理及回收算法

Java类加载器及如何加载类(双亲委派)

xml解析方式

Statement和PreparedStatement之间的区别

JavaEE:

servlet生命周期及各个方法

servlet中如何自定义filter

JSP原理

JSP和Servlet的区别

JSP的动态include和静态include

Struts中请求处理过程

MVC概念

Spring mvc与Struts区别

Hibernate/Ibatis两者的区别

Hibernate一级和二级缓存

Hibernate实现集群部署

Hibernate如何实现声明式事务

简述Hibernate常见优化策略

Spring bean的加载过程(推荐看Spring的源码)

Spring如何实现AOP和IOC

Spring bean注入方式

Spring的事务管理(推荐看Spring的源码)

Spring事务的传播特性

springmvc原理

springmvc用过哪些注解

Restful有几种请求

Restful好处

Tomcat,Apache,JBoss的区别

memcached和redis的区别

有没有遇到中文乱码问题,如何解决的

如何理解分布式锁

你知道的开源协议有哪些

json和xml区别

设计模式:

设计模式的六大原则

常用的设计模式

用一个设计模式写一段代码或画出一个设计模式的UML

如何理解MVC

高内聚,低耦合方面的理解

算法:

深度优先、广度优先算法

排序算法及对应的时间复杂度和空间复杂度

写一个排序算法

查找算法

B+树和二叉树查找时间复杂度

KMP算法、hash算法

常用的hash算法有哪些

如何判断一个单链表是否有环?

给你一万个数,如何找出里面所有重复的数?用所有你能想到的方法,时间复杂度和空间复杂度分别是多少?

给你一个数组,如何里面找到和为K的两个数?

100000个数找出最小或最大的10个?

一堆数字里面继续去重,要怎么处理?

数据结构:

队列、栈、链表、树、堆、图

编码实现队列、栈

Linux:

linux常用命令

如何查看内存使用情况

Linux下如何进行进程调度

操作系统:

操作系统什么情况下会死锁

产生死锁的必要条件

死锁预防

数据库:

范式

数据库事务隔离级别

数据库连接池的原理

乐观锁和悲观锁

如何实现不同数据库的数据查询分页

SQL注入的原理,如何预防

数据库索引的实现(B+树介绍、和B树、R树区别)

SQL性能优化

数据库索引的优缺点以及什么时候数据库索引失效

Redis的存储结构

网络:

OSI七层模型以及TCP/IP四层模型

HTTP和HTTPS区别

HTTP报文内容

get提交和post提交的区别

get提交是否有字节限制,如果有是在哪限制的

TCP的三次握手和四次挥手

session和cookie的区别

HTTP请求中Session实现原理

redirect与forward区别

DNS

TCP和UDP区别

安全:

如果客户端不断的发送请求连接会怎样

DDos攻击

DDos预防

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章