前言 这个是我自己看的面试题,如果解答有问题,请指教
就是这个博客提到面试题
- 操作系统中 heap 和 stack 的区别
堆的特点是类似于排队:先进先出,后进后出,类似于商场排队,使用于java的数据的存储阶段,用于存储java 创建的变量
栈的特点是:先进后出,后进先出,类似像箱子里面放书,拿出来的过程,栈使用于java程序的执行阶段
- 什么是基于注解的切面实现
切面的实现实际上说的aop的思想,这里我介绍spring aspactJ aop实现方式:
aop用于记录事件方法 前置方法(before),后置方法(aftert),异常方法(afterThrows),返回方法(afterReturn),环绕方法(around)
aop 有些概念 切面,切点(一般指要记录的方法)之类的东西
- 什么是 Java 的反射机制
java 特有的在程序运行期间获取 类的字段,方法,执行类的方法,添加类的属性的特性称为 java类的反射机制
- 什么是 ACID
acid值得事物的特性:
A:原子性: 一个事物要么发生,要不发生发生回滚,事物是一个整体,不可分离
C:一致性: 存在事物的2个或者多个事件,必须同时改变事物发生之前的状态或者是改变到事物发生之后的状态
B:隔离性:
2. spring七个事务传播属性:
1.PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
2.PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。
3.PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。
4.PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。
5.PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_NEVER – 以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED – 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
备注:常用的两个事务传播属性是1和4,即PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW
3. 五个隔离级别:
ISOLATION_DEFAULT
这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与JDBC的隔离级别相对应;
ISOLATION_READ_UNCOMMITTED
这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
ISOLATION_REPEATABLE_READ
这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
ISOLATION_SERIALIZABLE
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
除了防止脏读,不可重复读外,还避免了幻像读。
关键词:
Ø 脏读:一个事务读取了另一个未提交的并行事务写的数据。
Ø 不可重复读:一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。
Ø 幻读:一个事务重新执行一个查询,返回一套符合查询条件的行, 发现这些行因为其他最近提交的事务而发生了改变。
脏读:指一个事务读取了一个未提交事务的数据
不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同.一个事务读取到了另一个事务提交后的数据.
虚读(幻读):在一个事务内读取了别的事务插入的数据,导致前后读取不一致(insert)
D:持久性:事物提交以后,数据的改变应该是持久性
7、Cookie 和 Session 的区别
Cookie 指的是对系统的一次请求将请求的内容缓存在浏览器,在浏览器为关闭之前都可以在任意页面都可以访问到这个对象
Session 是浏览器和服务器之间的交互,系统将数据缓存在服务器端的对象
8、get 和 post请求的区别
传输的数据量:get传输的数据量是有限的,post传输的数据量是无限的
安全性:get传递的参数是明文传输不安全,post可以传递http包中所以安全性高一些
功能上:post 执行的请求一般为跟新操作,get执行的请求类型一般为获取数据的操作
9、 finalize() 方法的使用
在这里插入代码片
1、final关键字有哪些用法
- 使用在字段上面 fina static Stirng name 说明name这个变量不可以改变了,属于常量
- 使用在方法上说明这个方法不能被其他类继承
- 使用在类上说明这个类不能被继承
2、final 与 static 关键字可以用于哪里?它们的作用是什么
1.static 可以用在类的成员变量上面,也可以用在方法上面,static修饰的成员变量和方法可以通过类直接访问,而不是创建对象才能访问,static修饰的变量创建所有对象都能访问得到
2.static修饰的方法里面不可以访问非static修饰的变量
3.单类中有些数据只需加载一次那么可以放在static{}里面
例如:
class Person{
private Date birthDate;
private static Date startDate,endDate;
static{
startDate = Date.valueOf("1946");
endDate = Date.valueOf("1964");
Date startDate = Date.valueOf("1946");//对比与这样创建的方式
Date endDate = Date.valueOf("1964");//
}
public Person(Date birthDate) {
this.birthDate = birthDate;
}
boolean isBornBoomer() {
return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
}
}
这样创建的效率更高一些
4. static 和 构造方法执行先后的问题
执行的时候 static{} 代码块是在类加载的时候就执行,所以先执行类的static{},然后再执行构造方法
执行方法的时候 先执行父类的static和构造方法再执行子类的static模块和构造方法
public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
执行次序:
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor
3、final, finally, finalize的区别
finally 一般用在 try{}catch(Exception e){}finally{} 这里面的finally指的是无论是否捕获到异常我们都执行finally里面的内容
4、final、finalize 和 finally 的不同之处?
5、能否在运行时向 static final 类型的赋值
不能
6、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变
7、一个类被声明为final类型,表示了什么意思
8、throws, throw, try, catch, finally分别代表什么意义
throws 使用在方法的头中用于抛出各种异常 public void test() throws Exception{}
throws 使用在方法的代码之中例如
if(money<1000){
throw new Exception("货币金额不足");
}
try{
// 可能出现异常的代码
}catch(Exception e){
// 捕获到的异常信息
}finally{
// 最终要执行的代码无论有无捕获到异常信息
}
1、switch 语句中的表达式可以是什么类型数据
byte ,short ,int char,String (必须是jdk1.7),枚举类型
2、switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上
不能 long的范围大于int了,switch原则上只能使用int
3、while 循环和 do 循环有什么不同
while 满足条件的时候循环体执行,do先执行循环体,再判断条件
1、&操作符和&&操作符有什么区别?
& 表示且 表达式1&表达式2 当表达式满足条件时 就不判断了,&& 都会判断
2、a = a + b 与 a += b 的区别?
如果限制了 a和b为同一种数据类型 例如 byte,int限制无区别,java 中的5 默认为int类型,如果a类型byte类型则会报错 a+=b却不会
3、逻辑操作符 (&,|,^)与条件操作符(&&,||)的区别
4、3*0.1 == 0.3 将会返回什么?true 还是 false?
false
5、float f=3.4; 是否正确?
不正确 3.4 为double 类型
6、short s1 = 1; s1 = s1 + 1;有什么错?
跟2一个错误
1、基础类型(Primitives)与封装类型(Wrappers)的区别在哪里
2、简述九种基本数据类型的大小,以及他们的封装类
类型 大小 分装类 默认值
byte -128 ~127 Integer 0
short 2^-16 ~ 2^16-1 Short 0
int 2^-32 ~ 2^32-1 Integer 0
Long 2^-64~ 2^64-1 Ingeter
浮点型 :
float 2^-32 ~ 2^32 -1 Float 0.0
double 2^-64 ~ 2^64-1 Double 0.0
布尔类型:
boolean 2^-8 ~ 128 Boolean false
字符类型:
char 2^-64 ~ 2^64-1 Character 空
3、int 和 Integer 哪个会占用更多的内存? int 和 Integer 有什么区别?parseInt()函数在什么时候使用到
4、float和double的默认值是多少
0.0,0.0
5、如何去小数四舍五入保留小数点后两位
6、char 型变量中能不能存贮一个中文汉字,为什么
能,一个汉字占2个字节,char的范围大于字节存储数所以可以存储汉字
1、怎样将 bytes 转换为 long 类型
直接转就可以了,
byte a =4;
long b =(long)a
2、怎么将 byte 转换为 String
byte num = 3;
String.valueOf(num)
3、如何将数值型字符转换为数字
String a = "123";
int b = Integer.Intparse(a);
4、我们能将 int 强制转换为 byte 类型的变量吗?如果该值大于 byte 类型的范围,将会出现什么现象
可以,byte只能存储到127 ,当int 数值大于127时,那么就会丢失精度,存进去的最大值为127
5、能在不进行强制转换的情况下将一个 double 值赋值给 long 类型的变量吗
不行,有小数,只能通过强制类型转换,并且丢失精度
1、如何权衡是使用无序的数组还是有序的数组
在这里插入代码片
2、怎么判断数组是 null 还是为空
3、怎么打印数组? 怎样打印数组中的重复元素
Arrays.asList(数组)
遍历数组当元素出现2次以上打印出来
代码:
/**
* <p>Title: ArrayTest.java</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2017</p>
* <p>Company:kehui</p>
* @author jiangcl
* @date 2018年10月13日
* @version 1.0
*/
package com.mvc.test;
import java.util.HashMap;
import java.util.Map;
/**
* <p>Title: ArrayTest</p>
* <p>Description: </p>
* @author jiangcl
* @date 2018年10月13日
*/
public class ArrayTest {
public static void main(String[] args) {
String[] arr = new String[]{"jiang","jiang","test","ooo","test","pppp"};
Map<String,Integer> map = new HashMap<String,Integer>();
for(int i = 0 ;i<arr.length;i++){
int appNum = 0;
for(int j = 0;j<arr.length;j++){
if(arr[i].equals(arr[j])){
appNum++;
}
}
if(appNum>=2){
map.put(arr[i], appNum);
}
}
System.out.println(map.toString());
}
}
4、Array 和 ArrayList有什么区别?什么时候应该使用Array而不是ArrayList
5、数组和链表数据结构描述,各自的时间复杂度
数组:按照顺序进行数据的存储,在内存中是连续排列的,当查询的时候根据数组的下标,进行查询,删除或者插入的时候需要重新移动下标,将数据重新存储一遍,所以数组的查询速度快而删除和插入较慢
链表:链表的存储是不连续的,一个节点上存储着本节点的数据和下一个节点的内存地址,在查询时需要将每个节点都查询一遍以获取下一个节点的数据,所以查询数据慢,删除和插入的时候,将节点删除不影响节点数据结构所以删除和插入较快,但是查询较慢
数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n);
数组插入或删除元素的时间复杂度O(n),链表的时间复杂度O(1)
6、数组有没有length()这个方法? String有没有length()这个方法
没有,有
1、队列和栈是什么,列出它们的区别
2、BlockingQueue是什么
3、简述 ConcurrentLinkedQueue LinkedBlockingQueue 的用处和不同之处。
4、ArrayList、Vector、LinkedList 的存储性能和特性?
ArrayList 查询数据快,删除,插入速度慢,底层基于数组的方式
Vector 查询速度较ArrayList 慢一些,vector里面大量方法使用了,同步代码块字段,所以线程安全
LinkedList 插入和删除的速度较快,查询速度较慢,底层基于链表的结构
5、String 和 StringBuffer,StringBuilder 的区别?
StringBuffer 是线程安全的,但是字符串的拼接效率低于StringBuilder ,
StringBuffer 的线程安全是通过synchronized 实现的
6、ByteBuffer 与 StringBuffer 有什么区别?
1、HashMap的工作原理是什么
https://www.cnblogs.com/chengxiao/p/6059914.html
2、HashMap内部的数据结构是什么
HashMap 底层是由数组和链表实现的,hashMap的主干实际上是一个entry数组,里面存放key-value的数据
3、HashMap 的 table的容量如何确定?loadFactor 是什么? 该容量如何变化?这种变化会带来什么问题?
4、HashMap 实现的数据结构是什么?如何实现
5、HashMap 和 HashTable、ConcurrentHashMap 的区别
HashMap 线程不安全,但是查询,删除,插入的效率较HashTable较高,
HashTable线程安全,
ConcurrentHashMap
6、HashMap的遍历方式及效率
for(Map.Entry<String, String> entry:map.entrySet()){
System.out.println(entry.getKey()+entry.getValue());
}
7、HashMap、LinkedMap、TreeMap的区别
linkedMap 会保持数据插入的顺序,但是查询速度较慢
TreeMap 会给数据自动排序
8、如何决定选用HashMap还是TreeMap
9、如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办
增加2倍的容量
10、HashMap 是线程安全的吗?并发下使用的 Map 是什么,它们内部原理分别是什么,比如存储方式、 hashcode、扩容、 默认容量等
1、HashSet和TreeSet有什么区别
2、HashSet 内部是如何工作的
3、WeakHashMap 是怎么工作的?
1、Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢?是用 == 还是 equals()? 它们有何区别?
当数据为基本数据类型的时候,我们比较内容 使用的equal方法的方式进行比较
当数据为引用类型时候,我们比较内存地址
2、TreeMap:TreeMap 是采用什么树实现的?TreeMap、HashMap、LindedHashMap的区别。TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?
3、TreeSet:一个已经构建好的 TreeSet,怎么完成倒排序。
4、EnumSet 是什么
1、Hashcode 的作用
hashcode是内存地址
2、简述一致性 Hash 算法
3、有没有可能 两个不相等的对象有相同的 hashcode?当两个对象 hashcode 相同怎么办?如何获取值对象
4、为什么在重写 equals 方法的时候需要重写 hashCode 方法?equals与 hashCode 的异同点在哪里
5、a.hashCode() 有什么用?与 a.equals(b) 有什么关系
6、hashCode() 和 equals() 方法的重要性体现在什么地方
7、Object:Object有哪些公用方法?Object类hashcode,equals 设计原则? sun为什么这么设计?Object类的概述
8、如何在父类中为子类自动完成所有的 hashcode 和 equals 实现?这么做有何优劣。
9、可以在 hashcode() 中使用随机数字吗?
1、什么是线程
线程指的是cpu完成一系列进程的操作
2、多线程的优点
合理的利用cpu资源,提高工作效率
3、多线程的几种实现方式
java的多线程主要有继承Thread类和实现runnable接口的方式实现的
4、用 Runnable 还是 Thread
都是可以的,要根据实际的场景
5、什么是线程安全
当一个方法正在被访问那么其他的线程就不能再访问这个方法了,必须等到这个方法被执行完,其他线程才能访问,这样的模式就叫线程安全
6、Vector, SimpleDateFormat 是线程安全类吗
Vector是线程安全的集合,SimpleDateFormat并非线程安全的类
7、什么 Java 原型不是线程安全的
8、哪些集合类是线程安全的
Vector,HashTable,CurrentHashMap等
9、多线程中的忙循环是什么
忙循环就是程序员用循环让一个线程等待,不像传统方法wait(), sleep() 或 yield() 它们都放弃了CPU控制,而忙循环不会放弃CPU,它就是在运行一个空循环。这么做的目的是为了保留CPU缓存,在多核系统中,一个等待线程醒来的时候可能会在另一个内核运行,这样会重建缓存。为了避免重建缓存和减少等待重建的时间就可以使用它了。
10、如何创建一个线程
/**
* <p>Title: Thread.java</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2017</p>
* <p>Company:kehui</p>
* @author jiangcl
* @date 2018年10月10日
* @version 1.0
*/
package com.mvc.test.thread;
/**
* <p>Title: Thread</p>
* <p>Description: </p>
* @author jiangcl
* @date 2018年10月10日
*/
public class ThreadTest {
//线程的创建主要由继承Thread方法和实现runnable接口的方式
public static void main(String[] args) {
// 使用 继承Thread方式创建
Thread1 th1 = new Thread1();
// 使用接口方式创建
Thread2 th2 = new Thread2();
Thread th3 = new Thread(th2,"线程2");
// 直接创建
new Thread(){
public void run(){
System.out.println("直接使用thread方式创建线程");
}
}.start();
// start() 是线程的启动方法
th1.start();
th3.start();
}
}
11、编写多线程程序有几种实现方式
12、什么是线程局部变量
共享单个变量:
/**
* <p>Title: ShareParam.java</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2017</p>
* <p>Company:kehui</p>
* @author jiangcl
* @date 2018年10月14日
* @version 1.0
*/
package com.mvc.test.thread;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* <p>Title: ShareParam</p>
* <p>Description: </p>
* @author jiangcl
* @date 2018年10月14日
*/
public class ShareParam extends Thread{
List<Integer> list = new ArrayList<Integer>();
int printTimes = 0;
boolean stopFlag = true;
long startTime = System.currentTimeMillis();
public void run(){
while(stopFlag){
printTimes++;
list.add(printTimes);
System.out.println(Thread.currentThread().getName()+"打印的次数为:"+printTimes);
if(printTimes ==90){
stopFlag = false;
System.out.println(list.toString());
long endTime = System.currentTimeMillis();
System.out.println("花费的时间为:"+(endTime-startTime));
}
}
}
}
/**
* <p>Title: ShareTest.java</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2017</p>
* <p>Company:kehui</p>
* @author jiangcl
* @date 2018年10月14日
* @version 1.0
*/
package com.mvc.test.thread;
/**
* <p>Title: ShareTest</p>
* <p>Description: </p>
* @author jiangcl
* @date 2018年10月14日
*/
public class ShareTest {
public static void main(String[] args) {
ShareParam p = new ShareParam();
Thread th1 = new Thread(p);
Thread th2 = new Thread(p);
th1.setName("线程1");
th2.setName("线程2");
th1.start();
th2.start();
}
}
13、线程和进程有什么区别?进程间如何通讯,线程间如何通讯
进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程:进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
14、什么是多线程环境下的伪共享(false sharing)
15、同步和异步有何异同,在什么情况下分别使用他们?举例说明
1、启动一个线程是调用 run() 还是 start() 方法?start() 和 run() 方法有什么区别
start() 是调用线程启动的方法,start() 方法是从底层启动了,线程启动方法,run是线程的执行体,也是线程里面的普通,方法,有start()调用,使用线程直接run()达不到并发执行任务的目的
2、调用start()方法时会执行run()方法,为什么不能直接调用run()方法
3、sleep() 方法和对象的 wait() 方法都可以让线程暂停执行,它们有什么区别
sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,
将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态,请参考第66题中的线程状态转换图)。
wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lockpool),如果线程重新获得对象的锁就可以进入就绪状态
4、yield方法有什么作用?sleep() 方法和 yield() 方法有什么区别
yield()是线程执行完释放出资源,供其他线程使用
5、Java 中如何停止一个线程
一般使用while循环使用一个boolean变量控制while循环,如果这个boolean值改变就退出循环退出线程
6、stop() 和 suspend() 方法为何不推荐使用
7、如何在两个线程间共享数据
不能够在线程内使用局部变量,使用成员变量并且使用static修饰
8、如何强制启动一个线程
9、如何让正在运行的线程暂停一段时间
使用sleep()方法或者使用wait()方法,2个方法的区别是sleep()在休眠线程以后,会获取线程的锁,这个其他线程处于阻塞状态,而wait()在停止线程以后会释放锁,让其他线程有机会去竞争这个锁,不会阻塞线程的执行
10、什么是线程组,为什么在Java中不推荐使用
11、你是如何调用 wait(方法的)?使用 if 块还是循环?为什么
1、有哪些不同的线程生命周期
1.线程的创建(2种方式)
2.线程的就绪状态
3.线程的开启
4.线程执行
线程的挂起
线程的休眠
5.线程的结束
2、线程状态,BLOCKED 和 WAITING 有什么区别
3、画一个线程的生命周期状态图
4、ThreadLocal 用途是什么,原理是什么,用的时候要注意什么
1、请说出你所知的线程同步的方法
多线程在同时操作同一个变量的时候,会出现错误,所以我们需要同步操作同一个变量,这个就是线程同步,使用线程同步一般使用synchronized关键字的方法或者代码块
2、synchronized 的原理是什么
就是给synchronized修饰的方法加锁,使线程必须执行完以后,其他线程才能执行这个方法
3、synchronized 和 ReentrantLock 有什么不同
4、什么场景下可以使用 volatile 替换 synchronized
5、有T1,T2,T3三个线程,怎么确保它们按顺序执行?怎样保证T2在T1执行完后执行,T3在T2执行完后执行
/**
* <p>Title: RR.java</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2017</p>
* <p>Company:kehui</p>
* @author jiangcl
* @date 2018年10月18日
* @version 1.0
*/
package com.mvc.test.thread;
/**
* <p>Title: RR</p>
* <p>Description: </p>
* @author jiangcl
* @date 2018年10月18日
*/
public class JoinTest {
public static void main(String [] args) throws InterruptedException {
ThreadJoinTest t1 = new ThreadJoinTest("线程1");
ThreadJoinTest t2 = new ThreadJoinTest("线程2");
ThreadJoinTest t3 = new ThreadJoinTest("线程3");
t1.start();
/**join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是:
程序在main线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕
所以结果是t1线程执行完后,才到主线程执行,相当于在main线程中同步t1线程,t1执行完了,main线程才有执行的机会
*/
t1.join();
t3.start();
t3.join();
t2.start();
}
}
class ThreadJoinTest extends Thread{
public ThreadJoinTest(String name){
super(name);
}
@Override
public void run(){
System.out.println(Thread.currentThread().getName()+"执行了");
}
}
6、同步块内的线程抛出异常会发生什么
7、当一个线程进入一个对象的 synchronized 方法A 之后,其它线程是否可进入此对象的 synchronized 方法B
不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁
8、使用 synchronized 修饰静态方法和非静态方法有什么区别
9、如何从给定集合那里创建一个 synchronized 的集合