在使用锁的时候一些有趣的问题
📣 📣 📣 📢📢📢
☀️☀️你好啊!小伙伴,我是小冷。是一个兴趣驱动自学练习两年半的的Java工程师。
📒 一位十分喜欢将知识分享出来的Java博主⭐️⭐️⭐️,擅长使用Java技术开发web项目和工具
📒 文章内容丰富:覆盖大部分java必学技术栈,前端,计算机基础,容器等方面的文章
📒 如果你也对Java感兴趣,关注小冷吧,一起探索Java技术的生态与进步,一起讨论Java技术的使用与学习
✏️高质量技术专栏专栏链接: 微服务, 数据结构, netty, 单点登录, SSM , SpringCloudAlibaba等
😝公众号😝 : 想全栈的小冷,分享一些技术上的文章,以及解决问题的经验
⏩ 当前专栏: JUC系列
8锁现象
锁 ----> 刚new 出来的对象、class
8锁就是关于的锁的八个问题,下面也有四个demo类来阐述各种场景下锁的不同状态
demo1
两个问题:
正常模式下 在两个同步线程方法调用的时候 中途延时1s 会不会改变输出结果
答:不会影响输出顺序
正常模式下 同步方法内延时4s 会不会印象输出
答:不会影响输出顺序
- 标准情况下 两个线程打印 发短信还是打电话 1/ 发短信 2/打电话
- 发短信延时四秒 两个线程打印 发短信还是打电话 1/ 发短信 2/打电话
demo代码
package lock8;
import java.util.concurrent.TimeUnit;
/**
* @projectName: JUC
* @package: Lock8
* @className: lock8Demo
* @author: 冷环渊 doomwatcher
* @description: TODO
* Lock8 就是关于锁的八个问题
* 1. 标准情况下 两个线程打印 发短信还是打电话 1/ 发短信 2/打电话
* 2. 发短信延时四秒 两个线程打印 发短信还是打电话 1/ 发短信 2/打电话
* @date: 2022/3/2 1:13
* @version: 1.0
*/
public class lock8Demo {
public static void main(String[] args) {
phone phone = new phone();
new Thread(() -> {
phone.sendSms();
}, "A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
}, "B").start();
}
}
class phone {
//synchronized 锁的对象是方法调用者,
//两个方法用的都是 phone 对象的锁,两个方法谁先拿到锁 谁执行
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
demo2
同步方法执行和普通方法执行顺序
答 :普通方法没有锁,所以普通方法先
两个对象执行会不会影响顺序
答:会 两个不同的对象锁也是不同的 ,对象1 还在等待,对象2调用的call方法不用等待所以先输出
- 现在新增一个普通方法 问 先发短信还是先发hello 先输出hello
- 新增两个对象 是先打电话还是先发短信
package lock8;
import java.util.concurrent.TimeUnit;
/**
* @projectName: JUC
* @package: Lock8
* @className: lock8Demo
* @author: 冷环渊 doomwatcher
* @description: TODO
* Lock8 就是关于锁的八个问题
* 3、 现在新增一个普通方法 问 先发短信还是先发hello 先输出hello
* 4、 新增两个对象 是先打电话还是先发短信
* @date: 2022/3/2 1:13
* @version: 1.0
*/
public class lock8Demo2 {
public static void main(String[] args) {
//两个对象,现在是两个调用者所以是两个锁
phone2 phone = new phone2();
phone2 phone1 = new phone2();
new Thread(() -> {
phone.sendSms();
}, "A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
}, "B").start();
}
}
class phone2 {
//synchronized 锁的对象是方法调用者,
//两个方法用的都是 phone 对象的锁,两个方法谁先拿到锁 谁执行
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
//因为这里没有锁,不受锁的影响
public void hello() {
System.out.println("hello");
}
}
demo3
一个对象调用静态同步方法会不会改动执行顺序
答: 不会 ,static是锁的类模版全局唯一,不会改变锁的执行交换顺序
两个对象调用静态同步方法会不会改变执行顺序
答:不会 static修饰的是类模版,锁的也是类模板而不是类对象,只要是这个类生成的对象,不管多少个都不会改变顺序
- 一个对象 添加两个静态的同步方法,只有一个对象 先打印 发短信 还是打电话?
- 添加两个对象,分别调用静态同步方法 先打印 发短信 还是打电话?
package lock8;
import java.util.concurrent.TimeUnit;
/**
* @projectName: JUC
* @package: Lock8
* @className: lock8Demo
* @author: 冷环渊 doomwatcher
* @description: TODO
* Lock8 就是关于锁的八个问题
* 5、添加两个静态的同步方法,只有一个对象 先打印 发短信 还是打电话?
* 6、 添加两个对象,增加两个同步方法 先打印 发短信 还是打电话?
* @date: 2022/3/2 1:13
* @version: 1.0
*/
public class lock8Demo3 {
public static void main(String[] args) {
//不管多少对象, 使用的都是底层的唯一class所以不管怎么怎么改变结果都不会变,
// 因为synchroized锁的是class对象,static修饰的方法 类一开始就加载了,
new Thread(() -> {
Phone3.sendSms();
}, "A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
Phone3.call();
}, "B").start();
}
}
//phone3是唯一的一个class
class Phone3 {
//synchronized 锁的对象是方法调用者,
//两个方法用的都是 phone 对象的锁,两个方法谁先拿到锁 谁执行
// 这里 static 是静态方法 ,类一加载就有了,这个用的锁不再是 phone锁 而是class锁
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}
demo4
- 一个静态方法和一个普通加锁方法, 先打印 发短信 还是打电话? 先出打电话,因为锁的不是一个东西,sync锁的是类,static 是锁class
- 两个对象 一个静态方法和一个普通加锁方法, 先打印 发短信 还是打电话? 先出打电话,
答: 不是同一个锁,谁执行快就输出谁,
package lock8;
import java.util.concurrent.TimeUnit;
/**
* @projectName: JUC
* @package: Lock8
* @className: lock8Demo
* @author: 冷环渊 doomwatcher
* @description: TODO
* Lock8 就是关于锁的八个问题
* 7、一个静态方法和一个普通加锁方法, 先打印 发短信 还是打电话? 先出打电话,因为锁的不是一个东西,sync锁的是类,static 是锁class
* 8、两个对象 一个静态方法和一个普通加锁方法, 先打印 发短信 还是打电话? 先出打电话,
* @date: 2022/3/2 1:13
* @version: 1.0
*/
public class lock8Demo4 {
public static void main(String[] args) {
Phone4 phone = new Phone4();
//不管多少对象, 使用的都是底层的唯一class所以不管怎么怎么改变结果都不会变,
// 因为synchroized锁的是class对象,static修饰的方法 类一开始就加载了,
new Thread(() -> {
Phone4.sendSms();
}, "A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
}, "B").start();
}
}
//phone3是唯一的一个class
class Phone4 {
//静态同步方法是锁的 class
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
//这里普通同步方法锁的是 phone
public synchronized void call() {
System.out.println("打电话");
}
}
小结
我们通过八种不同的情况来理解锁在不同情况下的执行情况:
- 标准情况下 两个线程打印 发短信还是打电话 1/ 发短信 2/打电话
- 发短信延时四秒 两个线程打印 发短信还是打电话 1/ 发短信 2/打电话
- 现在新增一个普通方法 问 先发短信还是先发hello 先输出hello
- 新增两个对象 是先打电话还是先发短信
- 一个对象 添加两个静态的同步方法,只有一个对象 先打印 发短信 还是打电话?
- 添加两个对象,分别调用静态同步方法 先打印 发短信 还是打电话?
- 一个静态方法和一个普通加锁方法, 先打印 发短信 还是打电话? 先出打电话,因为锁的不是一个东西,sync锁的是类,static 是锁class
- 两个对象 一个静态方法和一个普通加锁方法, 先打印 发短信 还是打电话? 先出打电话,
大家可以自己写一下代码看一些这些问题的结果,实践出效果,实践出理解
锁的东西,无非就是对象和 类模版
- new 出来的对象 就是锁具体的对象,比如普通同步方法
- 带有static 修饰的静态同步方法 锁的是类模版是全局唯一的对象class如 : class