如何判断锁的是什么?
首先我们先来看下面的代码。思考下面两个问题。
/**
* 1.Q:下面程序执行后,是先打印 “看电影” 还是 “玩游戏” 呢? A:先打印“看电影”
* 2.Q:若watchMovie方法延迟4秒,是先打印 “看电影” 还是 “玩游戏” 呢? A:先打印“看电影” */
public class Test01 {
public static void main(String[] args){
TV tv = new TV();
new Thread(()->{
tv.watchMovie();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
tv.playGame();
},"B").start();
}
}
class TV{
public synchronized void watchMovie(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("看电影");
}
public synchronized void playGame(){
System.out.println("打游戏");
}
}
synchronized 锁的对象是方法的调用者!
就上面代码而言,看电影和玩游戏两个方法是用的TV对象的一把锁,所以谁先拿到谁先执行!
我们在思考下面两个问题。
/**
* 3.Q:增加了一个普通方法后,是先打印 “开机” 还是 “看电影” 呢? A:先打印“开机”
* 4.Q:若两个对象,两个同步方法,是先打印 “看电影” 还是 “打游戏” 呢? A:先打印“打游戏” */
public class Test02 {
public static void main(String[] args){
TV2 tv1 = new TV2();
TV2 tv2= new TV2();
new Thread(()->{
tv1.watchMovie();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
tv2.playGame();
},"B").start();
}
}
class TV2{
public synchronized void watchMovie(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("看电影");
}
public synchronized void playGame(){
System.out.println("打游戏");
}
public void open(){
System.out.println("开机");
}
}
就问题3而言,我们之前了解过synchronized 锁的对象是方法的调用者!而普通方法没有synchronized修饰,不受锁控制,所以先执行。
就问题4而言,两个对象,就是两个调用者,也就意味着有两把锁,所以要受时间延迟影响,先打印“打游戏”!
好的,那我们再看下面两组问题:
/**
* 5.Q:增加两个静态方法,只有一个对象,是先打印 “看电影” 还是 “玩游戏” 呢? A:先打印“看电影”
* 6.Q:若两个对象,两个静态方法,是先打印 “看电影” 还是 “玩游戏” 呢? A:先打印“看电影” */
public class Test03 {
public static void main(String[] args){
TV3 tv1 = new TV3();
TV3 tv2 = new TV3();
new Thread(()->{
tv1.watchMovie();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
tv2.playGame();
},"B").start();
}
}
class TV3{
public static synchronized void watchMovie(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("看电影");
}
public static synchronized void playGame(){
System.out.println("打游戏");
}
}
static 静态,全局唯一,static 方法在类加载的时候就存在了,synchronized 锁static 方法本质是锁TV对象的Class模板,类的Class模板只有一个,换而言之,调用者只有一个,锁只有一把,所以还是谁先拿到谁先执行!
最后再来看下面两个问题:
/**
* 7.Q:增加1个静态 synchronized 方法,1个普通 synchronized 方法,只有一个对象,是先打印 “看电影” 还是 “打游戏” 呢? A:先打印“打游戏”
* 8.Q:增加1个静态 synchronized 方法,1个普通 synchronized 方法,两个对象,是先打印 “看电影” 还是 “打游戏” 呢? A:先打印“打游戏” */
public class Test04 {
public static void main(String[] args){
TV4 tv1 = new TV4();
TV4 tv2 = new TV4();
new Thread(()->{
tv1.watchMovie();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
tv2.playGame();
},"B").start();
}
}
class TV4{
public static synchronized void watchMovie(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("看电影");
}
public synchronized void playGame(){
System.out.println("打游戏");
}
}
就问题7而言,静态synchronized方法和普通synchronized锁的调用者不是一个,前者是类的Class模板,后者是对象,所以有两个调用者,也就存在两把锁,因此,时间延迟的原因占主导。同理问题8也是如此,两个调用者两把锁!
总结:关键理解锁的对象是方法的调用者!锁的对象无外乎两种,一种是new的对象,而一种就是Class模板。要分清具体情况下究竟锁的是什么?