经典的8锁问题

8锁问题

8锁就是8个锁的问题,直接探究出到底锁的是谁:
借用一个Phone类,里面有打电话和发短信两个方法,答案就是先发短信还是先打电话:

1.两个同步方法,一个对象调用。

那么是先发短信还是先打电话呢?

 

/**
 * @Description:
 * @Package: com.nerr.lock8
 * @ClassName: demo01
 * @Author: nerr
 * @Date: 2021/6/22
 * @Version: 1.0
 */
public class Demo01 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(()->{
            phone.sms();
        },"a").start();
        new Thread(()->{
            phone.call();
        },"b").start();
    }
}
class Phone{
    public synchronized void sms(){
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}

  

答案是:先发短信

解释:synchronized 锁的是方法的调用者,也就是对象锁。两个方法持有的是同一把锁,因此谁先拿到锁谁先执行

 

2.两个同步方法,两个对象调用。

那么是先发短信还是先打电话呢?发短信先沉睡3秒钟

 


import java.util.concurrent.TimeUnit;

public class Demo02 {
public static void main(String[] args) {
Phone2 phone = new Phone2();
Phone2 phone1 = new Phone2();
new Thread(()->{
phone.sms();
},"a").start();
new Thread(()->{
phone1.call();
},"b").start();
}
}
class Phone2{
public synchronized void sms(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}

 

答案是先打电话

原因:synchronized 锁的是方法的调用者,也就是对象锁。两个对象分别调用两个方法持有的是两把把锁,打电话不需要等待。如果不沉睡,锁的是对象,因为是不同的两个对象,所以并不受锁的影响。

 

3.一个同步方法,一个普通方法,一个对象调用

新增一个 打游戏,描述:发短信沉睡3秒,打游戏为普通方法

 

import java.util.concurrent.TimeUnit;

/*
一个同步方法,一个普通方法,一个对象调用
让发短信沉睡3秒
*/
public class Demo03 {
public static void main(String[] args) {
Phone3 phone = new Phone3();

new Thread(()->{
phone.sms();
},"a").start();
new Thread(()->{
phone.call();
},"b").start();
new Thread(()->{
phone.game();
},"c").start();
}
}
class Phone3{
public synchronized void sms(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
public void game(){
System.out.println("打游戏");
}
}

 

答案是:打游戏=>发短信=>打电话

原因:普通方法没有锁,不需要竞争锁。

 

 

4.两个同步方法,一个对象调用

 描述:让发短信先沉睡3秒

 


/*
两个同步方法,一个对象调用
*/
import java.util.concurrent.TimeUnit;

public class Demo04 {
public static void main(String[] args) {
Phone4 phone = new Phone4();

new Thread(() -> {
phone.sms();
}, "a").start();
new Thread(() -> {
phone.call();
}, "b").start();
}
}
class Phone4{
public synchronized void sms(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}

 

答案是:先发短信

原因:synchronized 锁的是方法的调用者,也就是对象锁。两个方法持有的是同一把锁,因此谁先拿到锁谁先执行

 

 

5、两个静态同步方法,一个对象调用

描述:发短信沉睡3秒钟

 

/*
两个静态同步方法,一个对象调用
*/
import java.util.concurrent.TimeUnit;

public class Demo05 {
public static void main(String[] args) {
Phone5 phone = new Phone5();

new Thread(() -> {
Phone5.sms();
}, "a").start();
new Thread(() -> {
Phone5.call();
}, "b").start();
}
}
class Phone5{
public static synchronized void sms(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}

 

答案:先发短信

原因:static方法类一加载就会执行,synchronized 锁的是Class对象,所以两个方法持有一把锁,谁先得到谁先执行

 

 

6、 两个静态同步方法,两个对象调用

描述:发短信沉睡3秒

/*
两个静态同步方法,两个对象调用
*/
import java.util.concurrent.TimeUnit;

public class Demo06 {
public static void main(String[] args) {
Phone6 phone = new Phone6();
Phone6 phone6 = new Phone6();

new Thread(() -> {
Phone6.sms();
}, "a").start();

new Thread(() -> {
Phone6.call();
}, "b").start();
}
}
class Phone6{
public static synchronized void sms(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}

 

答案:先打电话

static方法类一加载就执行,synchronized 锁的是Class对象即类所,两个方法持有两把把锁,而打电话不沉睡3秒

 

 

7、一个静态同步方法,一个普通同步方法,一个对象调用

import java.util.concurrent.TimeUnit;

public class Demo07 {
public static void main(String[] args) {
Phone7 phone = new Phone7();

new Thread(() -> {
Phone7.sms();
}, "a").start();

new Thread(() -> {
phone.call();
}, "b").start();
}
}
class Phone7{
public static synchronized void sms(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}

 

答案:先打电话

原因:静态同步方法和普通同步方法分别是类锁和对象锁,相当于两把锁,普通同步方法不要等待。

 

8、一个静态同步方法,一个普通同步方法,两个对象调用

import java.util.concurrent.TimeUnit;

public class Demo08 {
    public static void main(String[] args) {
        Phone8 phone = new Phone8();
        Phone8 phone8 = new Phone8();

        new Thread(() -> {
            Phone8.sms();
        }, "a").start();

        new Thread(() -> {
            phone8.call();
        }, "b").start();
    }
}
class Phone8{
    public static synchronized void sms(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}

 

答案:先打电话

原因:静态同步方法和普通同步方法分别是类锁和对象锁,相当于两把锁,普通同步方法不要等待。

 

 

总结:
普通带锁方法:锁对象,同一对象下的才按顺序执行,如果是同一个类下的不同对象则不受影响。

普通不带锁方法:不受任何影响。

静态带锁方法:锁类,同一个类下的所有对象的所有带锁方法都得按顺序执行。

 

经典的8锁问题

上一篇:ip协议


下一篇:JSP---根据值实现checkbox多选