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();
这个时候,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对象的锁
当前线程持有了两把锁,锁的对象分别是两个不同的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还有很多种使用方法,但只有明白是那条线程获得哪个对象的锁,就很容易明白了。