通过不动代码下线程的执行先后,让我们来深入理解锁!
下面都是基于一个基本案例,对于类phone来说,有两个方法,一个打电话,一个发短信
- 标准情况下,两个线程会按什么顺序执行呢?为了排除随机性,让call方法延迟2秒
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
try {
phone.call();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
phone.Text();
}).start();
}
}
class Phone {
public synchronized void call() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
System.out.println("打电话");
}
public synchronized void Text() {
System.out.println("发短信");
}
}
输出结果是等待两秒,输出 打电话 然后输出 发短信
原因是 synchronized 锁的对象是方法的调用者,即两个方法用的是同一个锁,所以谁先拿到,谁就先执行
- 增加了一个普通方法输出Hello,会先输出谁呢?
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
try {
phone.call();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
phone.Text();
}).start();
phone.hello();
}
}
class Phone {
public synchronized void call() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
System.out.println("打电话");
}
public synchronized void Text() {
System.out.println("发短信");
}
public void hello(){
System.out.println("hello!");
}
}
结果是直接输出hello!然后分别是打电话和发短信
原因是hello不是同步方法没有被加锁,所以不受影响
- 如果两个方法分别对应两个对象先输出谁呢?
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
try {
phone1.call();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
phone2.Text();
}).start();
}
}
class Phone {
public synchronized void call() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
System.out.println("打电话");
}
public synchronized void Text() {
System.out.println("发短信");
}
}
输出结果是 发短信 然后输出 打电话
由于有两个对象,于是有了两个调用者,也就是有了两把锁,互相不会影响
- 如果两个同步方法是静态的,一个对象,先输出谁呢?
这个会和标准状态的顺序一样,不做讨论,重点是下面的
- 如果两个同步方法是静态的,两个个对象,先输出谁呢?
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
Phone phone1 = new Phone();
Phone phone2 = new Phone();
new Thread(() -> {
try {
phone1.call();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
phone2.Text();
}).start();
}
}
class Phone {
public static synchronized void call() throws InterruptedException {
TimeUnit.SECONDS.sleep(2);
System.out.println("打电话");
}
public static synchronized void Text() {
System.out.println("发短信");
}
}
结果是等待两秒,输出 打电话 然后输出 发短信
这是因为synchronized 锁的对象是方法的调用者,而静态方法在类一加载的时候就有了,因此synchronized锁的是Class对象,即类模板,而类模板在运行过程中是唯一的,不论是phone1还是phone2都是用的同一个类模板,因此先使用类模板的call方法会先执行
- 如果有一个是静态方法,另一个不是,一个对象或者两个对象的情况下,谁先输出呢?
结果都是先输出 发短信,再输出 打电话
这是因为对于静态方法synchronized 锁的是类模板,对于非静态方法,锁得是当前的调用者,所以两者不会互相干扰,因此延迟的打电话会后输出
总结
- 对于非静态的方法,synchronized锁得是this,即当前对象,具体的某一个手机
- 对于静态的方法,synchronized锁得是Class,即唯一的一个类模板,不同的同一个类模板创建的对象,只要使用这一个静态方法时,都会上锁