目录
我们锁的到底是什么(8个案例)
案例1
案例2
案例3
案例4
案例5
案例6
案例7
案例8
总结
我们锁的到底是什么(8个案例)
有a、b两个线程,我们基于如下代码进行改造:
public static void main(String[] args) {
Phone phoneA = new Phone();
new Thread(() -> {
phoneA.sendEmail();
}, "a").start();
try {
TimeUnit.MICROSECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->
{
phoneA.sendSMS();
}, "b").start();
}
}
class Phone {
public synchronized void sendEmail() {
System.out.println("sendEmail");
}
public synchronized void sendSMS() {
System.out.println("sendSMS");
}
}
请依次判断下在如下8个案例下,是先打印“sendEmail”?还是先打印“sendSMS”?
案例1
2个方法都是普通同步方法,方法内无其他逻辑(如下图)
结果:先打印“sendEmail”,再打印“sendSMS”
案例2
打印“sendEmail”的方法中,添加暂停3秒的
结果:(延迟3秒后)先打印“sendEmail”,再打印“sendSMS”
案例3
添加1个普通方法(无synchronized)
结果:先打印“hello”,(延迟3秒后)再打印“sendEmail”
案例4
有2个phone(两个线程使用不同的phone对象)
结果:先打印“sendSMS”,(延迟3秒后)再打印“sendEmail”
案例5
2个方法都是静态同步方法,只有一个phone(两个线程使用同一个phone对象)
结果:(延迟3秒后)先打印“sendEmail”,再打印“sendSMS”
案例6
2个方法都是静态同步方法,有2个phone(两个线程使用不同的phone对象)
结果:(延迟3秒后)先打印“sendEmail”,再打印“sendSMS”
案例7
1个方法是静态同步方法,1个方法是普通同步方法,有1个phone(两个线程使用同一个phone对象)
结果:先打印“sendSMS”,(延迟3秒后)再打印“sendEmail”
案例8
1个方法是静态同步方法,1个方法是普通同步方法,有2个phone(两个线程使用不同的phone对象)
结果:先打印“sendSMS”,(延迟3秒后)再打印“sendEmail”
总结
-
当对方法加synchronized关键字时,锁的是当前对象(this),所以即使是多线程只要调用的是同一个对象的synchronized方法,就需要串行执行(案例1和案例2),未被synchronized修饰的普通方法则不受影响(案例3)
-
如果是不同对象则不受影响(案例4),分别在自己的对象上加锁,不会影响到别的对象
-
当在带有“static”的方法上加了synchronized关键字时,锁的是当前类,无论几个对象,都要抢类的这一把锁,因而是否使用同一对象都会串行执行
-
对于同步代码块呢,锁的是sychronized括号的对象