java面试题200+

本文很多内容摘抄其他博客和资料,相应的地方有对应连接. 也有的内容没有写出来 而是给出了其他博主的博客(链接,主要来自csdn和博客园)
文章主要分为两部分:问题和答案(相应的答案在 “–” + 问题)
问题带"/“的为有答案的,带”*"的迷惑中后期完善,没有标记的还未写答案,持续更新
还有个小提示由于宽度限制有的内容显示不完全,最下方有滚动条,也可以点击鼠标滑轮然后左移,右移

一、Java 基础
/1. JDK 和 JRE 有什么区别?
/2. == 和 equals 的区别是什么?
/3. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
/4. final 在 java 中有什么作用?
/5. java 中的 Math.round(-1.5) 等于多少?
/6. String 属于基础的数据类型吗?
/7. java 中操作字符串都有哪些类?它们之间有什么区别?
/8. String str="i"与 String str=new String(“i”)一样吗?
/9. 如何将字符串反转?
/10. String 类的常用方法都有那些?
/11. 抽象类必须要有抽象方法吗?
/12. 普通类和抽象类有哪些区别?
/13. 抽象类能使用 final 修饰吗?
/14. 接口和抽象类有什么区别?
/15. java 中 IO 流分为几种?
*16. BIO、NIO、AIO 有什么区别?
/17. Files的常用方法都有哪些?

二、容器
/18. java 容器都有哪些?
/19. Collection 和 Collections 有什么区别?
/20. List、Set、Map 之间的区别是什么?
/21. HashMap 和 Hashtable 有什么区别?
/22. 如何决定使用 HashMap 还是 TreeMap?
/23. 说一下 HashMap 的实现原理?
/24. 说一下 HashSet 的实现原理?
/25. ArrayList 和 LinkedList 的区别是什么?
/26. 如何实现数组和 List 之间的转换?
/27. ArrayList 和 Vector 的区别是什么?
/28. Array 和 ArrayList 有何区别?
/29. 在 Queue 中 poll()remove()有什么区别?
/30. 哪些集合类是线程安全的?
/31. 迭代器 Iterator 是什么?
/32. Iterator 怎么使用?有什么特点?
/33. Iterator 和 ListIterator 有什么区别?
/34. 怎么确保一个集合不能被修改?

三、多线程
/35. 并行和并发有什么区别?
/36. 线程和进程的区别?
/37. 守护线程是什么?
/38. 创建线程有哪几种方式?
/39. 说一下 runnable 和 callable 有什么区别?
/40. 线程有哪些状态?
/41. sleep()wait() 有什么区别?
/42. notify()notifyAll()有什么区别?
/43. 线程的 run()start()有什么区别?
/44. 创建线程池有哪几种方式?
/45. 线程池都有哪些状态?
/46. 线程池中 submit()execute()方法有什么区别?
/47. 在 java 程序中怎么保证多线程的运行安全?
/48. 多线程锁的升级原理是什么?
/49. 什么是死锁?
/50. 怎么防止死锁?
/51. ThreadLocal 是什么?有哪些使用场景?
/52. 说一下 synchronized 底层实现原理?
/53. synchronizedvolatile 的区别是什么?
/54. synchronized 和 Lock 有什么区别?
/55. synchronized 和 ReentrantLock 区别是什么?
/56. 说一下 atomic 的原理?

四、反射
57. 什么是反射?
58. 什么是 java 序列化?什么情况下需要序列化?
59. 动态代理是什么?有哪些应用?
60. 怎么实现动态代理?

五、对象拷贝
61. 为什么要使用克隆?
62. 如何实现对象克隆?
63. 深拷贝和浅拷贝区别是什么?

六、Java Web
64. jsp 和 servlet 有什么区别?
65. jsp 有哪些内置对象?作用分别是什么?
66. 说一下 jsp 的 4 种作用域?
67. session 和 cookie 有什么区别?
68. 说一下 session 的工作原理?
69. 如果客户端禁止 cookie 能实现 session 还能用吗?
70. spring mvc 和 struts 的区别是什么?
71. 如何避免 sql 注入?
72. 什么是 XSS 攻击,如何避免?
73. 什么是 CSRF 攻击,如何避免?

七、异常
74. throwthrows 的区别?
75. finalfinally、finalize 有什么区别?
76. try-catch-finally 中哪个部分可以省略?
77. try-catch-finally 中,如果 catchreturn 了,finally 还会执行吗?
78. 常见的异常类有哪些?

八、网络
79. http 响应码 301302 代表的是什么?有什么区别?
80. forward 和 redirect 的区别?
81. 简述 tcp 和 udp的区别?
82. tcp 为什么要三次握手,两次不行吗?为什么?
83. 说一下 tcp 粘包是怎么产生的?
84. OSI 的七层模型都有哪些?
85. get 和 post 请求有哪些区别?
86. 如何实现跨域?
87. 说一下 JSONP 实现原理?

九、设计模式
88. 说一下你熟悉的设计模式?
89. 简单工厂和抽象工厂有什么区别?

十、Spring/Spring MVC
90. 为什么要使用 spring?
91. 解释一下什么是 aop?
92. 解释一下什么是 ioc?
93. spring 有哪些主要模块?
94. spring 常用的注入方式有哪些?
95. spring 中的 bean 是线程安全的吗?
96. spring 支持几种 bean 的作用域?
97. spring 自动装配 bean 有哪些方式?
98. spring 事务实现方式有哪些?
99. 说一下 spring 的事务隔离?
100. 说一下 spring mvc 运行流程?
101. spring mvc 有哪些组件?
102. @RequestMapping 的作用是什么?
103. @Autowired 的作用是什么?

十一、Spring Boot/Spring Cloud
104. 什么是 spring boot?
105. 为什么要用 spring boot?
106. spring boot 核心配置文件是什么?
107. spring boot 配置文件有哪几种类型?它们有什么区别?
108. spring boot 有哪些方式可以实现热部署?
109. jpa 和 hibernate 有什么区别?
110. 什么是 spring cloud?
111. spring cloud 断路器的作用是什么?
112. spring cloud 的核心组件有哪些?

十二、Hibernate
113. 为什么要使用 hibernate?
114. 什么是 ORM 框架?
115. hibernate 中如何在控制台查看打印的 sql 语句?
116. hibernate 有几种查询方式?
117. hibernate 实体类可以被定义为 final 吗?
118. 在 hibernate 中使用 Integer 和 int 做映射有什么区别?
119. hibernate 是如何工作的?
120. get()load()的区别?
121. 说一下 hibernate 的缓存机制?
122. hibernate 对象有哪些状态?
123. 在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
124. hibernate 实体类必须要有无参构造函数吗?为什么?

十三、Mybatis
125. mybatis 中 #{}和 ${}的区别是什么?
126. mybatis 有几种分页方式?
127. RowBounds 是一次性查询全部结果吗?为什么?
128. mybatis 逻辑分页和物理分页的区别是什么?
129. mybatis 是否支持延迟加载?延迟加载的原理是什么?
130. 说一下 mybatis 的一级缓存和二级缓存?
131. mybatis 和 hibernate 的区别有哪些?
132. mybatis 有哪些执行器(Executor)?
133. mybatis 分页插件的实现原理是什么?
134. mybatis 如何编写一个自定义插件?

十四、RabbitMQ
135. rabbitmq 的使用场景有哪些?
136. rabbitmq 有哪些重要的角色?
137. rabbitmq 有哪些重要的组件?
138. rabbitmq 中 vhost 的作用是什么?
139. rabbitmq 的消息是怎么发送的?
140. rabbitmq 怎么保证消息的稳定性?
141.rabbitmq 怎么避免消息丢失?
142. 要保证消息持久化成功的条件有哪些?
143. rabbitmq 持久化有什么缺点?
144. rabbitmq 有几种广播类型?
145. rabbitmq 怎么实现延迟消息队列?
146. rabbitmq 集群有什么用?
147. rabbitmq 节点的类型有哪些?
148. rabbitmq 集群搭建需要注意哪些问题?
149. rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?
150. rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?
151. rabbitmq 对集群节点停止顺序有要求吗?

十五、Kafka
152. kafka 可以脱离 zookeeper 单独使用吗?为什么?
153. kafka 有几种数据保留的策略?
154. kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
155. 什么情况会导致 kafka 运行变慢?
156. 使用 kafka 集群需要注意什么?

十六、Zookeeper
157. zookeeper 是什么?
158. zookeeper 都有哪些功能?
159. zookeeper 有几种部署模式?
160. zookeeper 怎么保证主从节点的状态同步?
161. 集群中为什么要有主节点?
162. 集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
163. 说一下 zookeeper 的通知机制?

十七、MySql
164. 数据库的三范式是什么?
165. 一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
166. 如何获取当前数据库版本?
167. 说一下 ACID 是什么?
168. char 和 varchar 的区别是什么?
169. floatdouble 的区别是什么?
170. mysql 的内连接、左连接、右连接有什么区别?
171. mysql 索引是怎么实现的?
172. 怎么验证 mysql 的索引是否满足需求?
173. 说一下数据库的事务隔离?
174. 说一下 mysql 常用的引擎?
175. 说一下 mysql 的行锁和表锁?
176. 说一下乐观锁和悲观锁?
177. mysql 问题排查都有哪些手段?
178. 如何做 mysql 的性能优化?

十八、Redis
179. redis 是什么?都有哪些使用场景?
180. redis 有哪些功能?
181. redis 和 memecache 有什么区别?
182. redis 为什么是单线程的?
183. 什么是缓存穿透?怎么解决?
184. redis 支持的数据类型有哪些?
185. redis 支持的 java 客户端都有哪些?
186. jedis 和 redisson 有哪些区别?
187. 怎么保证缓存和数据库数据的一致性?
188. redis 持久化有几种方式?
189.redis 怎么实现分布式锁?
190. redis 分布式锁有什么缺陷?
191. redis 如何做内存优化?
192. redis 淘汰策略有哪些?
193. redis 常见的性能问题有哪些?该如何解决?

十九、JVM
194. 说一下 jvm 的主要组成部分?及其作用?
195. 说一下 jvm 运行时数据区?
196. 说一下堆栈的区别?
197. 队列和栈是什么?有什么区别?
198. 什么是双亲委派模型?
199. 说一下类加载的执行过程?
200. 怎么判断对象是否可以被回收?
201. java 中都有哪些引用类型?
202. 说一下 jvm 有哪些垃圾回收算法?
203. 说一下 jvm 有哪些垃圾回收器?
204. 详细介绍一下 CMS 垃圾回收器?
205. 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
206. 简述分代垃圾回收器是怎么工作的?
207. 说一下 jvm 调优的工具?
208. 常用的 jvm 调优的参数都有哪些?


-- JDK 和 JRE 有什么区别?
jre包含jvm和java各种类库(api) 作为java程序的最小运行环境,而jdk中包含了jre以及各种java 开发工具如bin目录下的javac,jar,jcmd,jconsole等

-- == 和 equals 的区别是什么?
"==":
	1.比较基本数据类型
		比较的为两个对象的内容
	2.比较引用数据类型
		比较的为两个对象的内存地址
equals:
	继承自object,object对象中的equals默认比较的是两个对象的内存地址,但是在一些类比如String,Integer,Date等都覆盖了超类Object的equals方法,比较的为值的内容.
https://www.cnblogs.com/smyhvae/p/3929585.html

-- 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
在没有覆盖equals方法的前提下.两个hashCode相同的对象,equals不一定为true.但是equals为true的两个对象hasCode一定相同. 因为hashCode是已一定的算法去处理对象然后算出个数值.不同

-- final 在 java 中有什么作用?
	1.修饰类
		被final修饰的类不可以被继承
	2.修饰方法
		被final修饰的方法不可以被子类覆盖
		将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法(这里是private与重写的关系,应该和final无关)
	3.修饰变量
		a.基本数据类型:一经赋值后就不能再被更改
		b.引用数据类型:引用对象初始化后就不能再将应用指向其他对象(但该引用所指向的对象的内容是可以发生变化的。本质上是一回事,因为引用的值是一个地址,final要求值,即地址的值不发生变化)
		c.函数的参数类型:说明该参数是只读型的。即你可以读取使用该参数,但是无法改变该参数的值。
		注意:final修饰的函数必须显示初始化.有两种方法:
			1.在变量定义的时候直接赋值
			2.在对象构造函数中初始化
https://www.cnblogs.com/xiaoxi/p/6392154.html

-- java 中的 Math.round(-1.5) 等于多少?
-1
可以这么理解: -1.5 最近的整数有 -1 , -2 去较大的一个.

-- 位运算符 >> , << , >>>
https://blog.csdn.net/xiaochunyong/article/details/7748713

-- String 属于基础的数据类型吗?
不属于,他属于引用数据类型.
这里可能会问到基本数据类型和引用类型的区别,比如空间分配,String不可变等..

-- java 中操作字符串都有哪些类?它们之间有什么区别?
String, StringBuffer, StringBuilder
	String:
		一经创建则不可再被修改,在进行字符串拼接的时候实际上内部创建StringBuffer然后进行append操作最后返回toString,旧的对象会被回收.(线程不安全)
	StringBuffer:
		可变对象,在进行字符串拼接的时候不会重新创建对象.(线程安全)
	StringBuilder:
		作用和StringBuilder基本相同(不是线程安全的)
正常情况下执行速率 StringBuilder > StringBuffer > String
https://www.cnblogs.com/dolphin0520/p/3778589.html
https://www.cnblogs.com/su-feng/p/6659064.html

-- String str="i"与 String str=new String(“i”)一样吗?
不一样, str="i" 他会在常量池看有没有存在,若没有存在则会在堆中创建,然后将引用保存到方法区的常量池中,下次再用"="创建该对象时,在查常量池会发现已有然后直接指向常量池中的对象.new 出来的他不管常量池中有没有,都会在堆中直接分配内存.创建一个新的对象.

-- 如何将字符串反转?
//方法1 递归方法
public static String reverse1(String s) {
    int length = s.length();
    if (length <= 1){
        return s;
    }
    String left = s.substring(0, length / 2);
    String right = s.substring(length / 2, length);
    return reverse1(right) + reverse1(left);
}

//方法2 通过 charAt(int index)返回char值进行字符串拼接
public static String reverse2(String s) {
    int length = s.length();
    String reverse = "";
    for (int i = 0; i < length; i++)
        reverse = s.charAt(i) + reverse;
    return reverse;
}

//方法3 把字符串转换成字符数组倒叙拼接然后返回值

public static String reverse3(String s) {
    char[] array = s.toCharArray();
    String reverse = "";
    for (int i = array.length - 1; i >= 0; i--)
        reverse += array[i];
    return reverse;
}

//方法4 调用StringBuffer中的reverse方法
public static String reverse4(String s) {
    return new StringBuffer(s).reverse().toString();
}

//方法5 把字符串转换成字符数组首位对调位置
public static String reverse5(String orig) {
    char[] s = orig.toCharArray();
    int n = s.length - 1;
    int halfLength = n / 2;
    for (int i = 0; i <= halfLength; i++) {
        char temp = s[i];
        s[i] = s[n - i];
        s[n - i] = temp;
    }
    return new String(s);
}

//方法6
public static String reverse6(String s) {
    char[] str = s.toCharArray();
    int begin = 0;
    int end = s.length() - 1;
    while (begin < end) {
        str[begin] = (char) (str[begin] ^ str[end]);
        str[end] = (char) (str[begin] ^ str[end]);
        str[begin] = (char) (str[end] ^ str[begin]);
        begin++;
        end--;
    }
    return new String(str);
}

//方法7
public static String reverse7(String s) {
    char[] str = s.toCharArray();
    Stack<Character> stack = new Stack<Character>();
    for (int i = 0; i < str.length; i++)
        stack.push(str[i]);

    String reversed = "";
    for (int i = 0; i < str.length; i++)
        reversed += stack.pop();
    return reversed;
}
https://www.cnblogs.com/lanseyitai1224/p/6955609.html

-- String 类的常用方法都有那些?
contains,equals,substring,split,length,charAt,indexOf,isEmpty ...

-- 抽象类必须要有抽象方法吗?
抽象类可以不包含抽象方法(但是抽象类不可以直接实例化),包含抽象方法的类一定是抽象类

-- 普通类和抽象类有哪些区别?
	1.抽象类不能被实例化
	2.抽象类可以有构造函数,被继承时子类必须继承父类一个构造方法,抽象方法不能被声明为静态
	3.抽象方法只需申明,而无需实现,抽象类中可以允许普通方法有主体
	4.含有抽象方法的类必须申明为抽象类
	5.抽象的子类必须实现抽象类中所有抽象方法,否则这个子类也是抽象类

-- 抽象类能使用 final 修饰吗?
不能,final 用于修饰类时,类不可被继承,而抽象类需要被继承才能使用.

-- 接口和抽象类有什么区别?
抽象类:
public abstract class abstractClass { 单继承

    private int a; // 普通变量

    private static int b; //静态变量

    abstract void method1(); //抽象方法

    void method2(){ //普通方法

    }

    static{ //静态块

    }

    { //初始化块

    }

    public abstractClass(int a) { //构造器
        this.a = a;
    }


}
接口:
public interface InterfaceT{  //多实现

    int a = 0; //常量

    void method1(); //抽象方法

    static void method2(){ //静态方法(子类不可继承静态方法)
        System.out.println(1234);
    }

    default void method3(){ //默认方法(子类可继承默认方法,也可覆盖)
        System.out.println(1234);
    }
    
}

接口和抽象类的相似性
	1 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。
	2 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
接口和抽象类的区别
	1 接口里只能包含抽象方法,静态方法和默认方法,不能为普通方法提供方法实现,抽象类则完全可以包含普通方法。
	2 接口里只能定义静态常量,不能定义普通成员变量,抽象类里则既可以定义普通成员变量,也可以定义静态常量。
	3 接口不能包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
	4 接口里不能包含初始化块,但抽象类里完全可以包含初始化块。
	5 一个类最多只能有一个直接父类,包括抽象类,但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承不足。

	https://blog.csdn.net/chengqiuming/article/details/70139323
	https://blog.csdn.net/shy2794109/article/details/80854901 (默认方法)

-- java 中 IO 流分为几种?
|IO
| ├字符流
| │ ├Reader
| │ │-├BufferedReader
| │ │-└InputStreamReader
| │ │	└FileReader
| │ ├Writer
| │ │-├BufferWriter
| │ │-└OutputStreamWriter
| │ │	└FileWriter
| ├字节流
| │ ├InputStream
| │ │-├FileInputStream
| │ │-└FilterInputStream
| │ │	└BufferedInputStream
| │ ├OutputStream
| │ │-├FileOutputStream
| │ │-└FilterOutputStream
| │ │	└BufferOutputStream
https://blog.csdn.net/yuebinghaoyuan/article/details/7388059

-- *BIO、NIO、AIO 有什么区别?
BIO:同步阻塞IO
NIO:同步非阻塞IO
AIO:异步阻塞IO
https://www.jianshu.com/p/ef418ccf2f7d

-- Files的常用方法都有哪些
1	getName()			String	获取文件名称
2	canRead()			boolean	判断File是否可读,可读返回true
3	canWrite()			boolean	判断File是否可写,可写返回true
4	exists()			boolean	判断File是否存在,存在返回true
5	length()			long	获取File长度
6	getAbsolutePath()	String	获取File绝对路径
7	getParent()			String	获取File父目录
8	isFile();			boolean	判断File是否是文件,是文件返回true
9	isDirectory()		boolean	判断File是否是目录,是目录返回true
10	isHidden()			boolean	判断File是否是隐藏文件,是返回true
11	lastModified()		long	获取文件最后修改时间,时间是从1970 年午夜至最后修改时刻的毫秒数
12	mkdir()				boolean	创建目录,如果创建成功返回true,如果目录存在则不创建,并返回false

1	list()								String[]	返回目录下的所有文件名
2	listFiles()							File[]		返回目录下的全部文件对象
3	list(FilenameFilter filter)			String[]	返回目录下的所有文件名(filter用于指定过滤文件的类型)
4	listFiles(FilenameFilter filter)	File()		返回目录下的所有文件对象(filter用于指定过滤文件的类型)

-- java 容器都有哪些?
|Collection 
| ├List 
| │-├LinkedList 
| │-├ArrayList 
| │-└Vector 
| │ └Stack 
| ├Set 
| │-├HashSet 
| │-├TreeSet 
| │-└LinkedSet 
| 
|Map 
| ├Hashtable 
| ├HashMap 
| └WeakHashMap

-- Collection 和 Collections 有什么区别?
Collection为List,Set的接口类(集合类顶级接口).
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

-- List、Set、Map 之间的区别是什么?
List和set:直接保存对象的集合
	实现Collection接口
	List可保存重复对象而Set不行
	List对象顺序为放入的顺序(有序),而Set保存的对象(无序)
Map:以 键-值 保存,且key不可重复

-- HashMap 和 Hashtable 有什么区别?
HashMap键值都允许null,而Hashtable不允许null
HashMap线程不安全,Hashtable线程安全
为什么不安全?? : https://www.jianshu.com/p/e2f75c8cce01

-- 如何决定使用 HashMap 还是 TreeMap?
HashMap 无序基于hash找值
TreeMap 有序而TreeMap基于(红黑树)
通常情况下HashMap的效率高于TreeMap
https://blog.csdn.net/justloveyou_/article/details/71713781

-- 说一下 HashMap 的实现原理?
数组+链表
https://www.cnblogs.com/chengxiao/p/6059914.html#!comments

-- 说一下 HashSet 的实现原理?
基于HashMap.new HashSet()其实内部是创建一个HashMap,add(e)方法内部其实是hashmap.put(e,object) 其中object为final修饰的Object对象

-- ArrayList 和 LinkedList 的区别是什么
大部分情况下ArrayList查询较快,LinkedList插入较快
ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构;
https://www.cnblogs.com/shanheyongmu/p/6439202.html

-- 如何实现数组和 List 之间的转换?
List转换成数组可以使用List的toArray方法,返回一个Object数组。(Set也是)
如果List或Set中元素的类型都为A,那么可以使用带参数的toArray方法,得到类型为A的数组,具体语句是"list.toArray(new A[0])"。
数组转换成List可以使用Arrays的asList静态方法,得到一个List。
数组转化成Set时,需要先将数组转化成List再用List构造Set。

-- ArrayList 和 Vector 的区别是什么?
ArrayList在内存不够时默认是扩展50%[严格说是 newsize = oldsize + oldsize>>1, (oldsize>>1 : 偶数时为 n*50%,奇数时为(n-1)*50%],Vector是默认扩展1[如果new的时候用的Vector(int initialCapacity, int capacityIncrement)构造器时,Vector长度为initialCapacity,添加过程中若长度不够则将newsize = oldsize + capacityIncrement]。
Vector提供indexOf(obj, start)接口,ArrayList没有。 
Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。

-- Array 和 ArrayList 有何区别?
Array 可以保存基本数据类型(int int[] 可保存int,取出也为int),而ArrayList只能保存对象(Integer... 如果list.add(1),取出时的为Integer类型,会自动装箱)
Array 固定长度,定义后就不能修改.而ArrayList内部有自动扩容的机制

-- 在 Queue 中 poll()remove()有什么区别?
add      增加一个元索                如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove   移除并返回队列头部的元素     如果队列为空,则抛出一个NoSuchElementException异常
element  返回队列头部的元素          	如果队列为空,则抛出一个NoSuchElementException异常
offer    添加一个元素并返回true      	如果队列已满,则返回false
poll     移除并返问队列头部的元素     如果队列为空,则返回null
peek     返回队列头部的元素          	如果队列为空,则返回null
put      添加一个元素                	如果队列满,则阻塞
take     移除并返回队列头部的元素
https://www.cnblogs.com/samjustin/p/5785078.html 

-- 哪些集合类是线程安全的?
StringBuffer(内部基于数组),Vector,Hashtable,Stack

-- 迭代器 Iterator 是什么?
可以通过Iterator对实现了Iterable接口的类进行遍历
ArrayList实现了Collection,Collection继承了Iterable接口,也就是说ArrayList实现Collection接口后也需要重写Iterable的抽象方法,这里注意:ArrayList继承了AbstractList,在AbstractList中有个内部内Itr.这个Itr便是实现了Iterable接口以及实现了各个方法.ArrayList.iterator也是通过new Itr这个内部类实现的
如:ArrayList,HashSet,LinkedHashSet...

Set<Object> collection = new LinkedHashSet<>();

for (int i = 0; i < 10; i++) {
    collection.add(i);
}

Iterator<Object> iterator = collection.iterator();
while(iterator.hasNext()){
    System.out.println(iterator.next());
}

-- Iterator 怎么使用?有什么特点?
https://www.cnblogs.com/xujian2014/p/5846128.html

-- Iterator 和 ListIterator 有什么区别?
凡是实现了Collection接口的集合类,都有一个Iterator方法,用于返回一个实现了Iterator接口的对象,用于遍历集合;(Iterator接口定义了3个方法分别是hasNext(),next(),remove();)  
我们在使用List,Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator(迭代器)。使用迭代器,你不需要干涉其遍历的过程,只需要每次取出一个你想要的数据进行处理就可以了。
但是在使用的时候也是有不同的。List和Set都有iterator()来取得其迭代器。对List来说,你也可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的,Iterator和ListIterator主要区别在以下方面:
1. iterator()方法在set和list接口中都有定义,但是ListIterator()仅存在于list接口中(或实现类中);
2. ListIterator有add()方法,可以向List中添加对象,而Iterator不能
3. ListIterator和Iterator都有hasNext()next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
4. ListIterator可以定位当前的索引位置,nextIndex()previousIndex()可以实现。Iterator没有此功能。
5. 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。  
因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。

-- 怎么确保一个集合不能被修改?
Collections.unmodifiable*(..):unmodifiableSet(),unmodifiableList()
Collections中有以"unmodifiable"开头的方法,接收集合对象然后返回内容相同且不能被修改的集合对象(视图)
使用场景  ->  https://blog.csdn.net/cilen/article/details/7744969

-- 并行和并发有什么区别?
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。(不一定是同时的)
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
https://blog.csdn.net/weixin_30363263/article/details/80732156
https://blog.csdn.net/DreamWeaver_zhou/article/details/78587580

-- 线程和进程的区别?
进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位。
进程是线程的容器,不存在没有线程的进程

-- 守护线程是什么?
Java分为两种线程:用户线程和守护线程
所谓守护线程是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。
守护线程和用户线程的没啥本质的区别:唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。
https://www.cnblogs.com/lixuan1998/p/6937986.html

-- 创建线程有哪几种方式?
1.继承Thread
2.实现Runable接口
3.实现Callable接口
/**
 * 实现callable接口创建线程的方式
 * 注意其中FutureTask 实现了RunnableFuture接口,而RunnableFuture继承了Runnable接口
 * 因此可通过Thread的构造方法"public Thread(Runnable target, String name)"来创建线程
 */
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableThreadTest implements Callable<Integer>
{

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableThreadTest ctt = new CallableThreadTest();
        FutureTask<Integer> ft = new FutureTask<>(ctt);

        new Thread(ft,"有返回值的线程").start();
        System.out.println("子线程的返回值:"+ft.get());

    }

    @Override
    public Integer call() {
        System.out.println("successfully");
        return 123;
    }
}


-- 说一下 runnable 和 callable 有什么区别?
Runnable: 实现此接口后需重写run()方法且无返回值,可直接作为Thread构造器的参数来创建线程
Callable: 实现此接口后需重写call()方法,返回Integer.且需要通将Callable的实现类作为FutureTask的参数创建FutureTask实例然后再将FutureTask作为Thread构造器的参数来创建线程(如上 line:655)
通过Callable创建的线程可以将call方法执行过程中的异常抛给上级,也就是执行它的线程(如main方法)
FutureTask.get()可以取call方法中的返回值,如果获取不到或者线程未执行完毕,它会一直处于阻塞状态,直到获取到返回值.

-- 线程有哪些状态?
1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
3. 阻塞(BLOCKED):表示线程阻塞于锁。
4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
6. 终止(TERMINATED):表示该线程已经执行完毕。
https://blog.csdn.net/pange1991/article/details/53860651

-- sleep()wait() 有什么区别?
sleep() 方法是线程类Thread的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。 
因为sleep()static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。
wait() 是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程
https://blog.csdn.net/xyh269/article/details/52613507

-- notify()notifyAll()有什么区别?
关键词: 对象的锁池,等待池,锁
锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中

如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只有一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

import java.util.concurrent.TimeUnit;

public class WaitAndNotify {
    public static void main(String[] args) {
        Object co = new Object();
        System.out.println(co);

        for (int i = 0; i < 5; i++) {
            MyThread t = new MyThread("Thread" + i, co);
            t.start();
        }

        try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("-----Main Thread notify-----");
            synchronized (co) {
                co.notify();
            }

            TimeUnit.SECONDS.sleep(2);
            System.out.println("Main Thread is end.");

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class MyThread extends Thread {
        private String name;
        private Object co;

        public MyThread(String name, Object o) {
            this.name = name;
            this.co = o;
        }

        @Override
        public void run() {
            System.out.println(name + " is waiting.");
            try {
                synchronized (co) {
                    co.wait();
                }
                System.out.println(name + " has been notified.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
https://blog.csdn.net/djzhao/article/details/79410229

-- 线程的 run()start()有什么区别?
run()直接调用Thread方法,start()使线程进入可执行状态,等待cpu调度

-- 创建线程池有哪几种方式?
https://blog.csdn.net/Hsuxu/article/details/8985931
https://blog.csdn.net/mine_song/article/details/70948223
https://www.cnblogs.com/dolphin0520/p/3932921.html

-- 线程池都有哪些状态?
1、RUNNING
(1) 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。 
(02) 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为02、 SHUTDOWN
(1) 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。 
(2) 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。

3、STOP
(1) 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。 
(2) 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。

4、TIDYING
(1) 状态说明:当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。 
(2) 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。 
当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。

5、 TERMINATED
(1) 状态说明:线程池彻底终止,就变成TERMINATED状态。 
(2) 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。
https://blog.csdn.net/u011389515/article/details/80656813

-- 线程池中 submit()execute()方法有什么区别?
有无返回值,可接受参数类型
这里需要注意线程的创建方法中提到过实现Callable接口来创建线程,它和用继承Thread和实现Runnable接口最大的区别就是有返回值(line:640)
submit()可以接受Runnable和Callable类型的参数,可返回Future<?>对象,可通过Future.get()获取返回值.且内部是利用Callable的那种方式来执行线程最终执行的是call()execute()只能接受Runnable类型的参数,无返回值,内部是利用Runable那种方式来执行线程,最终执行的的run()

-- 在java程序中怎么保证多线程的运行安全?
三大原则:原子性,可见性,有序性   
关键字:synchronized,volatile,Atomic*....
https://blog.csdn.net/weixin_28760063/article/details/81266523

-- 多线程锁的升级原理是什么?
当一条线程需要请求一把已经被占用的锁时,并不会进入阻塞状态,而是继续持有CPU执行权等待一段时间,该过程称为『自旋』。
https://www.jianshu.com/p/7eb35976745c ()
http://blog.iluckymeeting.com/2018/01/06/threadandlocktwo/

-- 什么是死锁?
线程p1和p2分别持有数据a1和a2,p1和p2同时请求资源a2和a1,这时就会发生死锁(互相请求又互相持有,处于互相等待的状态)


-- 怎么防止死锁?
加锁顺序,加锁时限,死锁检测
死锁检测:
	每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。
	当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。例如,线程A请求锁7,但是锁7这个时候被线程B持有,这时线程A就可以检查一下线程B是否已经请求了线程A当前所持有的锁。如果线程B确实有这样的请求,那么就是发生了死锁(线程A拥有锁1,请求锁7;线程B拥有锁7,请求锁1)。
	当然,死锁一般要比两个线程互相持有对方的锁这种情况要复杂的多。线程A等待线程B,线程B等待线程C,线程C等待线程D,线程D又在等待线程A。线程A为了检测死锁,它需要递进地检测所有被B请求的锁。从线程B所请求的锁开始,线程A找到了线程C,然后又找到了线程D,发现线程D请求的锁被线程A自己持有着。这是它就知道发生了死锁。
https://blog.csdn.net/ls5718/article/details/51896159
http://www.importnew.com/21353.html

-- ThreadLocal 是什么?有哪些使用场景?
https://www.jianshu.com/p/98b68c97df9b

-- 说一下 synchronized 底层实现原理?
https://blog.csdn.net/javazejian/article/details/72828483

-- synchronizedvolatile 的区别是什么?
https://blog.csdn.net/SEU_Calvin/article/details/52370068

-- synchronized 和 Lock 有什么区别?
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
2synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5)Lock可以提高多个线程进行读操作的效率。
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
Lock有一个名为ReentrantLock的实现类可实现多线程同步(line:829)

-- synchronized 和 ReentrantLock 区别是什么?
他两都能实现同步,但是在使用synchronized的情况下,当A线程获取了某个对象的锁,B线程也想获得这个对象的锁,但是发现锁已经被A线程获取,这时就需要等待A线程释放锁以后才能继续获得锁.
而LocK在这种情况下可以不用一直等待.
Lock中的方法:
	lock():获取锁,如果锁被暂用则一直等待
	unlock():释放锁
	tryLock(): 注意返回类型是boolean,如果获取锁的时候锁被占用就返回false,否则返回true
	tryLock(long time, TimeUnit unit):比起tryLock()就是给了一个时间期限,保证等待参数时间
	lockInterruptibly():用该锁的获得方式,如果线程在获取锁的阶段进入了等待,那么可以中断此线程,先去做别的事

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

	public class Test {

	    private ArrayList<Integer> arrayList = new ArrayList<Integer>();

	    private Lock lock = new ReentrantLock();    //注意这个地方

	    public static void main(String[] args) throws InterruptedException {
	        final Test test = new Test();

	        new Thread(){
	            public void run() {
	                try {
	                    test.insert3(Thread.currentThread());
	                } catch (InterruptedException e) {
	                    e.printStackTrace();
	                }
	            }
	        }.start();

	        Thread thread2 = new Thread(){
	            public void run() {
	                try {
	                    test.insert3(Thread.currentThread());
	                } catch (InterruptedException e) {
	                    e.printStackTrace();
	                }
	            }
	        };

	        thread2.start();
	        Thread.sleep(1000);
	        thread2.interrupt(); //这里第二个线程已被设置成终端状态,在insert3中当第一个线程获取锁的时候 然后执行过程为4s,在此过程还未结束时第二个线程尝试获取锁,但是发现线程已经被设置为中断状态,这时就会终端第二个线程,并抛出异常:InterruptedException
	    }

	    public void insert(Thread thread) throws InterruptedException {

	        if (lock.tryLock(2,TimeUnit.SECONDS)){
	            try {
	                System.out.println(thread.getName()+"得到了锁");
	               Thread.sleep(4000);
	            } catch (Exception e) {
	                // TODO: handle exception
	            }finally {
	                System.out.println(thread.getName()+"释放了锁");
	                lock.unlock();
	            }
	        }else{
	            System.out.println(thread.getName()+"获取锁失败");
	            this.insert(thread);
	        }

	    }

	    public void insert2(Thread thread) {

	        synchronized ("sad"){
	            try {
	                System.out.println(thread.getName()+"得到了锁");
	                for(int i=0;i<5000;i++) {
	                    arrayList.add(i);
	                }
	                // TODO: handle exception
	            }finally {
	                System.out.println(thread.getName()+"释放了锁");

	            }
	        }

	    }

	    public void insert3(Thread thread) throws InterruptedException {
	        try {
	            lock.lockInterruptibly(); //可以根据Interrupted状态来终端线程.
	            System.out.println(thread.getName()+"得到了锁");
	            Thread.sleep(4000);
	        } catch (Exception e) {
	            // TODO: handle exception
	        }finally {
	            lock.unlock();
	            System.out.println(thread.getName()+"释放了锁");
	        }


	    }
	}


这里需要注意,还有个提供读写锁的接口"ReadWriteLock",它有个名为"ReentrantReadWriteLock"的实现类,可以通过这个实现类获取读锁(readLock)和写锁(writeLock),读锁在竞争锁的时候不等待,而写锁需要等待当前持有锁的线程执行完毕或者抛出异常时才会获取锁.


import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Test {
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
     
    public static void main(String[] args)  {
        final Test test = new Test();
         
        new Thread(){
            public void run() {
                test.get2(Thread.currentThread());
            };
        }.start();
         
        new Thread(){
            public void run() {
                test.get2(Thread.currentThread());
            };
        }.start();
         
    }  
     
    public synchronized void get(Thread thread) {
        long start = System.currentTimeMillis();
        while(System.currentTimeMillis() - start <= 1) {
            System.out.println(thread.getName()+"正在进行读操作");
        }
        System.out.println(thread.getName()+"读操作完毕");
    }

    public void get2(Thread thread) {
        long start = System.currentTimeMillis();
//        rwl.writeLock().lock();
        rwl.readLock().lock();
        try{
            while(System.currentTimeMillis() - start <= 1) {
                //                System.out.println(thread.getName()+"正在进行写操作");
                System.out.println(thread.getName()+"正在进行读操作");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
//            rwl.writeLock().unlock();
//            System.out.println(thread.getName()+"写操作完毕");
            rwl.readLock().unlock();
            System.out.println(thread.getName()+"读操作完毕");
        }


    }
}
https://www.cnblogs.com/baizhanshi/p/6419268.html
https://blog.csdn.net/SEU_Calvin/article/details/52401134

-- 说一下 atomic 的原理?
unsafe,CAS
https://www.jianshu.com/p/04cbf9c3e2c2
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liangh.orz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值