面试时候被问的问题,当时脑子里闪了一下,但是没答出来
先说结论:
- synchronized 修饰普通方法时,锁的是当前对象的方法,等价于 synchronized (this)
- synchronized 修饰静态方法时,锁的是所有对象的方法,等价于 synchronized (Xxx.class)
我们知道,普通方法从属于对象,而静态方法从属于类
带着疑惑,来看代码吧
情景1:当 synchronized 修饰 普通方法后,同一个对象被两个线程调用 结果
public class TestMain {
public static void main(String[] args) {
//测试 synchronized 修饰普通方法
Person person1 = new Person();
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("t1开始");
person1.work("t1线程老板 叫person1 工作啦");
System.out.println("t1结束");
}
};
Thread t2 = new Thread() {
@Override
public void run() {
System.out.println("t2开始");
person1.work("t2线程老板 叫person1 工作啦");
System.out.println("t2结束");
}
};
t1.start();
t2.start();
}
}
class Person{
//输出10次value work 方法
public synchronized void work(String value){
for (int i=0;i<10;i++){
System.out.println(value + i );
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
打印结果
t1开始
t2开始
t1线程老板 叫person1 工作啦0
t1线程老板 叫person1 工作啦1
t1线程老板 叫person1 工作啦2
t1线程老板 叫person1 工作啦3
t1线程老板 叫person1 工作啦4
t1线程老板 叫person1 工作啦5
t1线程老板 叫person1 工作啦6
t1线程老板 叫person1 工作啦7
t1线程老板 叫person1 工作啦8
t1线程老板 叫person1 工作啦9
t1结束
t2线程老板 叫person1 工作啦0
t2线程老板 叫person1 工作啦1
t2线程老板 叫person1 工作啦2
t2线程老板 叫person1 工作啦3
t2线程老板 叫person1 工作啦4
t2线程老板 叫person1 工作啦5
t2线程老板 叫person1 工作啦6
t2线程老板 叫person1 工作啦7
t2线程老板 叫person1 工作啦8
t2线程老板 叫person1 工作啦9
t2结束
上面代码我们可以看到,虽然 t1 和 t2 线程都开始了,但是 t2 线程并没有打断 t1 线程执行wok1 方法 (注意此时都是person1 一个对象)
情景2:synchronized 修饰普通方法后,不同对象被不同的线程调用结果
public class TestMain {
public static void main(String[] args) {
//测试 synchronized 修饰普通方法
Person person1 = new Person();
Person person2 = new Person(); // 修改
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("t1开始");
person1.work("t1线程老板 叫person1 工作啦");
System.out.println("t1结束");
}
};
Thread t2 = new Thread() {
@Override
public void run() {
System.out.println("t2开始");
person2.work("t2线程老板 叫person2 工作啦"); // 修改
System.out.println("t2结束");
}
};
t1.start();
t2.start();
}
}
class Person{
//输出10次value work1 方法
public synchronized void work(String value){
for (int i=0;i<10;i++){
System.out.println(value + i );
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
t1开始
t2开始
t1线程老板 叫person1 工作啦0
t2线程老板 叫person2 工作啦0
t1线程老板 叫person1 工作啦1
t2线程老板 叫person2 工作啦1
t2线程老板 叫person2 工作啦2
t1线程老板 叫person1 工作啦2
t1线程老板 叫person1 工作啦3
t2线程老板 叫person2 工作啦3
t1线程老板 叫person1 工作啦4
t2线程老板 叫person2 工作啦4
t2线程老板 叫person2 工作啦5
t1线程老板 叫person1 工作啦5
t1线程老板 叫person1 工作啦6
t2线程老板 叫person2 工作啦6
t2线程老板 叫person2 工作啦7
t1线程老板 叫person1 工作啦7
t1线程老板 叫person1 工作啦8
t2线程老板 叫person2 工作啦8
t1线程老板 叫person1 工作啦9
t2线程老板 叫person2 工作啦9
t2结束
t1结束
我们可以看到 ,这两个对象的方法在执行的过程中 都被打断了
情景3 : 情景2 的基础上 使用 static 修饰work方法
package com.demo06;
public class TestMain {
public static void main(String[] args) {
//测试 synchronized 修饰普通方法
Person person1 = new Person();
Person person2 = new Person(); // 修改
Thread t1 = new Thread() {
@Override
public void run() {
System.out.println("t1开始");
person1.work("t1线程老板 叫person1 工作啦");
System.out.println("t1结束");
}
};
Thread t2 = new Thread() {
@Override
public void run() {
System.out.println("t2开始");
person2.work("t2线程老板 叫person2 工作啦"); // 修改
System.out.println("t2结束");
}
};
t1.start();
t2.start();
}
}
class Person{
//输出10次value work1 方法
public static synchronized void work(String value){ //改动
for (int i=0;i<10;i++){
System.out.println(value + i );
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
t2开始
t2线程老板 叫person2 工作啦0
t1开始
t2线程老板 叫person2 工作啦1
t2线程老板 叫person2 工作啦2
t2线程老板 叫person2 工作啦3
t2线程老板 叫person2 工作啦4
t2线程老板 叫person2 工作啦5
t2线程老板 叫person2 工作啦6
t2线程老板 叫person2 工作啦7
t2线程老板 叫person2 工作啦8
t2线程老板 叫person2 工作啦9
t2结束
t1线程老板 叫person1 工作啦0
t1线程老板 叫person1 工作啦1
t1线程老板 叫person1 工作啦2
t1线程老板 叫person1 工作啦3
t1线程老板 叫person1 工作啦4
t1线程老板 叫person1 工作啦5
t1线程老板 叫person1 工作啦6
t1线程老板 叫person1 工作啦7
t1线程老板 叫person1 工作啦8
t1线程老板 叫person1 工作啦9
t1结束
我们可以看到,两个对象执行方法是又互不打断啦 。
到最后发现,我也可以说成 static 修饰 synchronized 方法后,使这个类的所有实例执行该方法时 都互不中断。synchronized 作用同步了所有的对象