博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,阿里云专家博主,华为云云享专家✌
💕💕 感兴趣的同学可以收藏关注下 ,不然下次找不到哟💕💕
写在前面
线程八锁是指在多线程环境下,使用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 对象的锁,因此它们使用的是不同的锁对象 。所以普通同步方法和静态同步代码块之间不会互斥执行,可以同时被多个线程访问。
💕💕 本文由激流原创,原创不易,感谢支持
💕💕喜欢的话记得点赞收藏啊