【字节一面】线程八锁

简介: 【字节一面】线程八锁

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

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

1688469560224.jpg

写在前面

线程八锁是指在多线程环境下,使用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 对象的锁,因此它们使用的是不同的锁对象 。所以普通同步方法和静态同步代码块之间不会互斥执行,可以同时被多个线程访问。

1686494501743.jpg

💕💕 本文由激流原创,原创不易,感谢支持
💕💕喜欢的话记得点赞收藏啊

1687869804912.jpg

目录
相关文章
|
16天前
|
Java
并发编程的艺术:Java线程与锁机制探索
【6月更文挑战第21天】**并发编程的艺术:Java线程与锁机制探索** 在多核时代,掌握并发编程至关重要。本文探讨Java中线程创建(`Thread`或`Runnable`)、线程同步(`synchronized`关键字与`Lock`接口)及线程池(`ExecutorService`)的使用。同时,警惕并发问题,如死锁和饥饿,遵循最佳实践以确保应用的高效和健壮。
26 2
|
7天前
|
分布式计算 并行计算 安全
在Python Web开发中,Python的全局解释器锁(Global Interpreter Lock,简称GIL)是一个核心概念,它直接影响了Python程序在多线程环境下的执行效率和性能表现
【6月更文挑战第30天】Python的GIL是CPython中的全局锁,限制了多线程并行执行,尤其是在多核CPU上。GIL确保同一时间仅有一个线程执行Python字节码,导致CPU密集型任务时多线程无法充分利用多核,反而可能因上下文切换降低性能。然而,I/O密集型任务仍能受益于线程交替执行。为利用多核,开发者常选择多进程、异步IO或使用不受GIL限制的Python实现。在Web开发中,理解GIL对于优化并发性能至关重要。
25 0
|
2月前
|
存储 安全 Java
深入理解Java并发编程:线程安全与锁机制
【5月更文挑战第31天】在Java并发编程中,线程安全和锁机制是两个核心概念。本文将深入探讨这两个概念,包括它们的定义、实现方式以及在实际开发中的应用。通过对线程安全和锁机制的深入理解,可以帮助我们更好地解决并发编程中的问题,提高程序的性能和稳定性。
|
4天前
|
调度 C语言
深入浅出:C语言线程以及线程锁
线程锁的基本思想是,只有一个线程能持有锁,其他试图获取锁的线程将被阻塞,直到锁被释放。这样,锁就确保了在任何时刻,只有一个线程能够访问临界区(即需要保护的代码段或数据),从而保证了数据的完整性和一致性。 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含一个或多个线程,而每个线程都有自己的指令指针和寄存器状态,它们共享进程的资源,如内存空间、文件句柄和网络连接等。 线程锁的概念
|
13天前
|
Java
Java中的`synchronized`关键字是一个用于并发控制的关键字,它提供了一种简单的加锁机制来确保多线程环境下的数据一致性。
【6月更文挑战第24天】Java的`synchronized`关键字确保多线程数据一致性,通过锁定代码块或方法防止并发冲突。同步方法整个方法体为临界区,同步代码块则锁定特定对象。示例展示了如何在`Counter`类中使用`synchronized`保证原子操作和可见性,同时指出过度使用可能影响性能。
23 4
|
17天前
|
安全 Java Python
GIL是Python解释器的锁,确保单个进程中字节码执行的串行化,以保护内存管理,但限制了多线程并行性。
【6月更文挑战第20天】GIL是Python解释器的锁,确保单个进程中字节码执行的串行化,以保护内存管理,但限制了多线程并行性。线程池通过预创建线程池来管理资源,减少线程创建销毁开销,提高效率。示例展示了如何使用Python实现一个简单的线程池,用于执行多个耗时任务。
21 6
|
20天前
|
API
linux---线程互斥锁总结及代码实现
linux---线程互斥锁总结及代码实现
|
18天前
|
调度
线程操作:锁、条件变量的使用
线程操作:锁、条件变量的使用
15 1
|
20天前
|
API
Linux---线程读写锁详解及代码实现
Linux---线程读写锁详解及代码实现
|
22天前
|
Java Python
Python中的并发编程(3)线程池、锁
Python中的并发编程(3)线程池、锁