1
使用==
的情况:
-
- 如果比较Integer变量,默认比较的是地址值。
- Java的Integer维护了从
-128~127
的缓存池 - 如果比较的某一边有操作表达式(例如a+b),那么比较的是具体数值
使用equals()
的情况:
-
- 无论是Integer还是Long中的
equals()
默认比较的是数值。 - Long的
equals()
方法,JDK的默认实现:会判断是否是Long类型
- 无论是Integer还是Long中的
-
注意自动拆箱,自动装箱问题。
2 锁消除
如果JVM明显检测到某段代码是线程安全的(言外之意:无锁也是安全的),JVM会安全地原有的锁消除掉!
Java面试题1:synchronized方法调用
1 1 synchronized同步方法调用另一个synchronized同步方法
public synchronized void methodA(int a, int b) {
};
public synchronized void methodB(int a){
methodA(a, 0);
}
答:
要明白两个问题,①锁的对象是谁;②谁持有了锁。
有三种情况:
(1)假设方法A和B是在同一个类Test中的两个方法。
Test t = new Test();
t.methodB();12
这个时候,methodB方法被调用时,因为加了synchronized ,需要先获得一个锁,这个锁的对象应该是t,也就是当前的这个Test类的实例,而获得锁的东西是线程,也就是说当前线程拿到了t的锁(而不是B方法获得锁),这个时候B方法内调用methodA,因为A也加了synchronized,也需要获得一个锁,因为A和B都是Test类中的方法,所以当前线程要获得的锁的对象也是t。由于当前线程在执行B方法时已经持有了t对象的锁,因此这时候调用methodA是没有任何影响的,相当于方法A上没有加synchronized。
**加在非static方法上的synchronized方法是和synchronized(this)块等价的,均为对象锁,即对this加锁。获得当前对象锁的线程,可以继续获得当前对象锁,JVM负责跟踪对象被加锁的次数。线程运行B方法,此时如果this锁可以用,线程获得该锁,线程给对象加锁,计数器变成1,然后B方法调用A方法,由于是对同一个对象同一个线程,线程可以继续获得锁,计数器变为2,表示this被加锁2次。**A方法完毕后,线程释放锁,计数器变为1,此时对象锁对其他线程依然是不可获得的。B方法完毕后,线程继续释放锁,此时计数器变为0,表示锁被完全释放,其他线程可以获得对象锁。
(2)假设现在有两个Test类
Test t1 = new Test();
Test t2 = new Test();
t1.methodB(); //此时当前线程持有了t1对象的锁
t2.methodB(); //此时当前线程也持有了t2对象的锁1234
当前线程持有了两把锁,锁的对象分别是两个不同的Test类的实例t1和t2,互相没有影响。
(3)假设在多线程环境下,两个线程都可以访问Test t=new Test();
此时假设thread1里调用t.methodB();同时thread2里调用t.methodB()
这时假设thread1先抢到t对象的锁,那么thread2需要等待thread1释放t对象的锁才可以执行B方法。
结果像这样:
thread1获得t的锁->thread1执行methodB->thread1执行methodA->释放t的锁;
thread2获得t的锁->thread2执行methodB->thread2执行methodA->释放t的锁。
synchronized还有很多种使用方法,但只有明白是那条线程获得哪个对象的锁,就很容易明白了。
问:
当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?
答:
不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的synchronized修饰符要求执行方法时要获得对象的锁,如果已经进入A方法说明对象锁已经被取走,那么试图进入B方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁。
拓展:
在Java中,每个对象都有两个池,锁(monitor)池和等待池
wait() ,notifyAll(),notify() 三个方法都是Object类中的方法.
锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁(因为wait()方法必须出现在synchronized中,这样自然在执行wait()方法之前线程A就已经拥有了该对象的锁),同时线程A就进入到了该对象的等待池中。如果另外的一个线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,准备争夺锁的拥有权。如果另外的一个线程调用了相同对象的notify()方法,那么**仅仅有一个处于该对象的等待池中的线程(随机)**会进入该对象的锁池.