一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized。
我们需要先弄清楚synchronized 在类方法上使用的两个关键点。
1.非静态方法的锁默认为 this,也就是我们所说的对象锁, 静态方法的锁为 对应的 Class 实例,也就是类锁。
2.某一个时刻内,只能有一个线程持有锁,无论几个方法。
例如:
/**
*
* @Description :synchronized方法
* @author Bush罗
* @date 2018年8月5日
*
*/
public class Main {
public static void main(String[] args) {
ThreadDemo demo1 = new ThreadDemo();
ThreadDemo demo2 = new ThreadDemo();
new Thread(new Runnable() {
@Override
public void run() {
demo1.getFrist();//1
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
demo1.getSecond();//2
//demo2.getSecond();//3
}
}).start();
}
}
class ThreadDemo {
public synchronized void getFrist() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
System.out.println("Frist");
}
public synchronized void getSecond() {
System.out.println("Second");
}
}
情况1:如上面代码一样.输出结果,先延迟三秒打印Frist,再打印Second。
两个线程操作的是同一个实例demo1,里面的synchronized方法是非静态方法,默认使用的是this这把对象锁,所以他们使用的是同一把锁,当线程1首先拿到这个锁时,线程2就被阻塞在方法外面进不来了,所以会先延迟三秒打印Frist,再打印Second。
情况2:.如果线程1执行demo1.getFrist();方法,线程2执行demo2.getSecond();方法,那么会先打印Second,然后延迟三秒打印Frist。
两个线程操作的是两个不同实例,那么就是两把不同的对象锁,所以是异步执行的,线程1与线程2互不干扰,所以先打印Second,然后延迟三秒打印Frist。
情况3:把getFrist()方法改成静态方法,然后线程1执行demo1.getFrist();方法,线程2执行demo1.getSecond();方法
public static synchronized void getFrist() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
System.out.println("Frist");
}
结果为:先打印Second,然后延迟三秒打印Frist。
因为getFrist()方法为静态方法,持有的锁为类锁,而getSecond不是静态方法,持有的锁为对象锁,两个线程虽然操作用一个实例,但是所拥有的锁不是同一把,所以是异步执行,先打印Second,然后延迟三秒打印Frist。
总结:
所有的非静态同步方法用的都是同一把锁一一实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
所有的静态同步方法用的也是同一把锁一一类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有亮态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!