【字节一面】线程八锁

180 阅读10分钟

博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,阿里云专家博主,华为云云享专家✌

💕💕 感兴趣的同学可以收藏关注下不然下次找不到哟💕💕

在这里插入图片描述

@[TOC]

写在前面

线程八锁是指在多线程环境下,使用synchronized关键字对代码进行同步时,可能出现的八种不同的情况。

线程八锁。也是常见的面试题,主要是针对锁对象的提问。

以下分别分析这8中情况。

1、普通同步方法和普通同步方法

==两个线程分别访问同一个对象的两个普通同步方法。由于普通方法默认使用的锁对象是this,因此这两个方法会互斥执行。==

以下是代码案例:

package com.pany.camp.thread.eight;

/**
 *
 * @description:  两个线程分别访问同一个对象的两个普通同步方法。
 *                由于普通方法默认使用的锁对象是this,因此这两个方法会互斥执行。
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-07-04 19:39 
 */
public class SynchronizedExample1 {

    public synchronized void method1() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行 method1.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行 method1.");
    }

    public synchronized void method2() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行 method2.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行 method2.");
    }

    public static void main(String[] args) {
        SynchronizedExample1 example = new SynchronizedExample1();

        Thread thread1 = new Thread(() -> {
            example.method1();
        });

        Thread thread2 = new Thread(() -> {
            example.method2();
        });

        thread1.start();
        thread2.start();
    }
}

其中有两个同步方法 method1 和 method2 。在 main 方法中,我们创建了两个线程来执行这些方法。由于这两个方法都是同步的,它们将使用相同的 锁对象( this ),因此两个线程将以互斥的方式执行这些方法。这意味着当一个线程执行 method1 时,另一个线程必须等待第一个线程完成执行,反之亦然。

2、静态同步方法和静态同步方法

==两个线程分别访问同一个类的两个静态同步方法。由于静态方法默认使用的锁对象是类的Class对象,因此这两个方法会互斥执行。==

以下是代码案例:

package com.pany.camp.thread.eight;

/**
 * @description: 两个线程分别访问同一个类的两个静态同步方法。
 * 由于静态方法默认使用的锁对象是类的Class对象,因此这两个方法会互斥执行。
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-07-04 19:44
 */
public class SynchronizedExample2 {
    public static synchronized void method1() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行 method1.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行 method1.");
    }

    public static synchronized void method2() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行 method2.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行 method2.");
    }

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            SynchronizedExample2.method1();
        });
        Thread thread2 = new Thread(() -> {
            SynchronizedExample2.method2();
        });
        thread1.start();
        thread2.start();
    }
}

其中有两个静态同步方法 method1 和 method2 。在 main 方法中,我们创建了两个线程来执行这些方法。由于这两个方法都是静态的,它们将使用 类的Class对象作为锁对象,因此两个线程将以互斥的方式执行这些方法。这意味着当一个线程执行 method1 时,另一个线程必须等待第一个线程完成执行,反之亦然。

3、静态同步方法和普通同步方法

==一个线程访问对象的普通同步方法,另一个线程访问类的静态同步方法。由于锁对象不同,因此这两个方法不会互斥执行。==

以下是代码案例:

package com.pany.camp.thread.eight;

/**
 * @description: 一个线程访问对象的普通同步方法,另一个线程访问类的静态同步方法。
 * 由于锁对象不同,因此这两个方法不会互斥执行。
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-07-04 19:52
 */
public class SynchronizedExample5 {
    public synchronized void method1() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行普通同步方法 method1.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行普通同步方法 method1.");
    }

    public static synchronized void method2() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行静态同步方法 method2.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行静态同步方法 method2.");
    }

    public static void main(String[] args) {
        SynchronizedExample5 example = new SynchronizedExample5();

        Thread thread1 = new Thread(() -> {
            example.method1();
        });

        Thread thread2 = new Thread(() -> {
            SynchronizedExample5.method2();
        });
        thread1.start();
        thread2.start();
    }
}

其中有一个普通同步方法 method1 和一个静态同步方法 method2 。在 main 方法中,我们创建了一个 SynchronizedExample 对象,并创建了两个线程来分别执行这两个方法。由于这两个方法使用不同的锁对象,,即 **一个是对象锁,一个是类锁,它们之间不会互斥执行。**这意味着当一个线程执行 method1 时,另一个线程可以同时执行 method2 ,它们之间没有互斥关系。

4、两个对象

==两个线程分别访问两个不同对象的同步方法。由于锁对象不同,因此这两个方法不会互斥执行。==

以下是代码案例:

package com.pany.camp.thread.eight;

/**
 * @description: 两个线程分别访问两个不同对象的同步方法。由于锁对象不同,因此这两个方法不会互斥执行。
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-07-04 19:49
 */
public class SynchronizedExample4 {

    public synchronized void method1() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行 method1.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行 method1.");
    }

    public synchronized void method2() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行 method2.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行 method2.");
    }

    public static void main(String[] args) {
        SynchronizedExample4 example1 = new SynchronizedExample4();
        SynchronizedExample4 example2 = new SynchronizedExample4();
        Thread thread1 = new Thread(() -> {
            example1.method1();
        });
        Thread thread2 = new Thread(() -> {
            example2.method2();
        });
        thread1.start();
        thread2.start();
    }
}

其中有一个同步方法 method1 和另一个同步方法 method2 。在 main 方法中,我们创建了两个 SynchronizedExample 对象,并创建了两个线程来分别执行这两个方法。由于这两个方法使 用不同的锁对象,即两个不同的 SynchronizedExample 对象,它们之间不会互斥执行。这意味着当一个线程执行 method1 时,另一个线程可以同时执行 method2 ,它们之间没有互斥关系。

5、普通同步方法和普通代码块

==同一个对象的普通同步方法和普通代码块之间是互斥的,因为它们使用的是同一个对象实例的锁。==

以下是代码案例:

package com.pany.camp.thread.eight;

/**
 * @description: 同一个对象的普通同步方法和普通代码块之间是互斥的,因为它们使用的是同一个对象实例的锁
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-07-04 19:52
 */
public class SynchronizedExample5 {
    public synchronized void synchronizedMethod() {
        // 同步方法
        System.out.println("进入同步方法");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("退出同步方法");
    }

    public void synchronizedBlock() {
        // 同步代码块
        synchronized (this) {
            System.out.println("进入同步代码块");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("退出同步代码块");
        }
    }

    public static void main(String[] args) {
        SynchronizedExample5 example = new SynchronizedExample5();

        // 创建两个线程,分别调用同步方法和同步代码块
        Thread thread1 = new Thread(() -> {
            example.synchronizedMethod();
        });

        Thread thread2 = new Thread(() -> {
            example.synchronizedBlock();
        });

        thread1.start();
        thread2.start();
    }
}

其中包含一个同步方法 synchronizedMethod() 和一个同步代码块 synchronizedBlock() 。在 main 方法中,我们创建了两个线程,分别调用这两个方法。

由于这两个方法都使用了 同一个对象实例的锁 (使用 synchronized 关键字修饰),因此同一个对象的同步方法和同步代码块之间是互斥的。即当一个线程进入同步方法时,另一个线程必须等待该方法执行完毕后才能进入同步代码块,反之亦然。

6、静态同步方法和静态代码块

==同一个类的静态同步方法和静态代码块之间是互斥的,因为它们使用的是类的Class对象的锁。==

以下是代码案例:

package com.pany.camp.thread.eight;

/**
 * @description: 对象的静态同步方法和静态代码块之间:同一个类的静态同步方法和静态代码块之间是互斥的,因为它们使用的是类的Class对象的锁
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-07-04 19:52
 */
public class SynchronizedExample6 {
    public static synchronized void synchronizedMethod() {
        // 静态同步方法
        System.out.println("进入静态同步方法");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("退出静态同步方法");
    }

    public static void synchronizedBlock() {
        // 静态同步代码块
        synchronized (SynchronizedExample6.class) {
            System.out.println("进入静态同步代码块");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("退出静态同步代码块");
        }
    }

    public static void main(String[] args) {
        // 创建两个线程,分别调用静态同步方法和静态同步代码块
        Thread thread1 = new Thread(() -> {
            SynchronizedExample6.synchronizedMethod();
        });

        Thread thread2 = new Thread(() -> {
            SynchronizedExample6.synchronizedBlock();
        });

        thread1.start();
        thread2.start();
    }
}


我们创建了一个 SynchronizedExample6 类,其中包含一个静态同步方法 synchronizedMethod() 和一个静态同步代码块 synchronizedBlock() 。在 main 方法中,我们创建了两个线程,分别调用这两个方法。

由于这两个方法都使用了 类的 Class 对象的锁(使用 synchronized 关键字修饰) ,因此同一个类的静态同步方法和静态同步代码块之间是互斥的。即当一个线程进入静态同步方法时,另一个线程必须等待该方法执行完毕后才能进入静态同步代码块,反之亦然。

7、静态方法和静态方法(同一类)

==两个线程分别访问同一个类的两个静态同步方法。由于静态方法默认使用的锁对象是类的Class对象,因此这两个方法会互斥执行。==

以下是代码案例:

package com.pany.camp.thread.eight;

/**
 * @description: 两个线程分别访问同一个类的两个静态同步方法。由于静态方法默认使用的锁对象是类的Class对象,因此这两个方法会互斥执行。
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-07-04 19:52
 */
public class SynchronizedExample7 {
    public static synchronized void method1() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行静态同步方法 method1.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行静态同步方法 method1.");
    }

    public static synchronized void method2() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行静态同步方法 method2.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程 " + Thread.currentThread().getName() + " 完成执行静态同步方法 method2.");
    }

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            SynchronizedExample7.method1();
        });
        Thread thread2 = new Thread(() -> {
            SynchronizedExample7.method2();
        });
        thread1.start();
        thread2.start();
    }
}




它有两个静态同步方法 method1 和 method2 。在 Main 类的 main 方法中,我们创建了两个线程来分别执行这两个方法。由于静态方法默认使用的 锁对象是类的Class对象 ,因此这两个方法会互斥执行。这意味着当一个线程执行 method1 时,另一个线程必须等待,直到第一个线程释放锁才能执行 method2 。因此,这两个方法之间是互斥的,不会同时执行。

8、普通同步方法和静态代码块

==一个线程访问对象的普通同步方法,另一个线程访问对象的非同步方法。由于锁对象不同,因此这两个方法不会互斥执行。==

以下是代码案例:

package com.pany.camp.thread.eight;

/**
 * @description: 不会互斥执行,因为它们使用的是不同的锁对象,一个是对象实例的锁,一个是类的Class对象的锁。
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-07-04 19:52
 */
public class SynchronizedExample8 {
    public synchronized void synchronizedMethod() {
        // 普通同步方法
        System.out.println("进入普通同步方法");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("退出普通同步方法");
    }

    public static void synchronizedBlock() {
        // 静态同步代码块
        synchronized (SynchronizedExample8.class) {
            System.out.println("进入静态同步代码块");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("退出静态同步代码块");
        }
    }

    public static void main(String[] args) {
        SynchronizedExample8 example = new SynchronizedExample8();
        // 创建两个线程,分别调用普通同步方法和静态同步代码块
        Thread thread1 = new Thread(() -> {
            example.synchronizedMethod();
        });

        Thread thread2 = new Thread(() -> {
            SynchronizedExample8.synchronizedBlock();
        });

        thread1.start();
        thread2.start();
    }
}


我们创建了一个 SynchronizedExample 类,其中包含一个普通同步方法 synchronizedMethod() 和一个静态同步代码块 synchronizedBlock() 。在 main 方法中,我们创建了一个 SynchronizedExample 对象,并创建了两个线程,分别调用这两个方法。

由于普通同步方法使用的是 对象实例的锁(使用 synchronized 关键字修饰),而静态同步代码块使用的是类的 Class 对象的锁,因此它们使用的是不同的锁对象 。所以普通同步方法和静态同步代码块之间不会互斥执行,可以同时被多个线程访问。

在这里插入图片描述

💕💕 本文由激流原创,原创不易,感谢支持 💕💕喜欢的话记得点赞收藏啊 在这里插入图片描述