关于锁的八个问题—八锁
前面的文章中留下一个疑问,到底什么是锁,锁到底锁的是谁?
这里我们就用打电话和发短信的例子来距离说明八锁问题—>锁的是对象方法的调用者或者Class模板(.class)
1、标准情况下,两个线程先打印 发短信还是 先打印 打电话?
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description
* @author: 不会编程的派大星
* @create: 2021-04-21 12:42
**/
public class Test1 {
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 锁的对象是方法的调用者!、
// 两个方法用的是同一个对象调用(同一个锁),谁先拿到锁谁执行!
public synchronized void sendSms(){
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
运行结果:
注:先发短信 —>这里锁的是phone对象,谁先拿到锁谁就先执行,发短信先
2.sendSms延迟4秒,两个线程先打印 发短信还是 打电话?
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description
* @author: 不会编程的派大星
* @create: 2021-04-21 12:52
**/
public class Test2 {
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 锁的对象是方法的调用者!、
// 两个方法用的是同一个对象调用(同一个锁),谁先拿到锁谁执行!
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(4);// 抱着锁睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
运行结果:
注:同样的,锁的phone对象,谁先拿到谁就用,先发短信
3、 增加了一个普通方法后!先执行发短信还是Hello?
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description
* @author: 不会编程的派大星
* @create: 2021-04-21 13:05
**/
public class Test3 {
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.hello();
},"B").start();
}
}
class Phone{
// synchronized 锁的对象是方法的调用者!、
// 两个方法用的是同一个对象调用(同一个锁),谁先拿到锁谁执行!
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");
}
}
运行结果:
注:hello方法不是同步方法,不受锁的限制,所以先执行
4、 两个对象,两个同步方法, 发短信还是 打电话?
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description
* @author: 不会编程的派大星
* @create: 2021-04-21 13:11
**/
public class Test4 {
public static void main(String[] args) {
// 两个对象,两个调用者,两把锁!
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
new Thread(()->{
phone2.hello();
},"C").start();
}
}
class Phone2{
// synchronized 锁的对象是方法的调用者!
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");
}
}
运行结果:
注:这里有两把锁,打电话和hello用的是phone2的锁,发短信用的是phone1的锁 ,两把锁这里互不影响,hello不受锁影响
5、增加两个静态的同步方法,只有一个对象,先打印 发短信?打电话?
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description
* @author: 不会编程的派大星
* @create: 2021-04-21 13:17
**/
public class Test5 {
public static void main(String[] args) {
// 两个对象的Class类模板只有一个,static,锁的是Class
Phone3 phone1 = new Phone3();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone1.call();
},"B").start();
}
}
// Phone3唯一的一个 Class 对象
class Phone3{
// synchronized 锁的对象是方法的调用者!
// static 静态方法
// 类一加载就有了!锁的是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("打电话");
}
}
运行结果:
注:这里只有一个锁,锁的时phone3.class(Class),在类加载时就已加锁,只有一把锁,所以先发短信
6、两个对象!增加两个静态的同步方法, 先打印 发短信?打电话?
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description
* @author: 不会编程的派大星
* @create: 2021-04-21 13:23
**/
public class Test6 {
public static void main(String[] args) {
// 两个对象的Class类模板只有一个,static,锁的是Class
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
// Phone3唯一的一个 Class 对象
class Phone3{
// synchronized 锁的对象是方法的调用者!
// static 静态方法
// 类一加载就有了!锁的是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("打电话");
}
}
运行结果:
注:这里虽有两个对象,但是因为static的存在,这里所得是phone3.class,所以还是只有一把锁,固还是先发短信
7、1个静态的同步方法,1个普通的同步方法 ,一个对象,先打印 发短信?打电话?
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description
* @author: 不会编程的派大星
* @create: 2021-04-21 13:27
**/
public class Test7 {
public static void main(String[] args) {
// 两个对象的Class类模板只有一个,static,锁的是Class
Phone4 phone1 = new Phone4();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone1.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("发短信");
}
// 普通的同步方法 锁的调用者(对象),二者锁的对象不同,所以不需要等待
public synchronized void call(){
System.out.println("打电话");
}
}
运行结果:
注:这里要注意了哦,有两把锁,发短信锁的是phone4.class,而打电话则是锁的phone1对象的调用者,两把锁,而打电话不需要延迟四秒,先拿到锁,所以先执行
8、1个静态的同步方法,1个普通的同步方法 ,两个对象,先打印 发短信?打电话?
import java.util.concurrent.TimeUnit;
/**
* @program: juc
* @description
* @author: 不会编程的派大星
* @create: 2021-04-21 13:31
**/
public class Test8 {
public static void main(String[] args) {
// 两个对象的Class类模板只有一个,static,锁的是Class
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
// 捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.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("发短信");
}
// 普通的同步方法 锁的调用者(对象),二者锁的对象不同,所以不需要等待
public synchronized void call(){
System.out.println("打电话");
}
}
运行结果:
注:这里和上面test7一样的,虽然有两个对象,但是还是两把锁,并且发短信锁的是phone4.class,打电话是phone2这个对象的调用者,而打电话没有延迟,先拿到锁,所以先执行。
7/8 两种情况下,都是先执行打电话,后执行发短信,因为二者锁的对象不同,
静态同步方法锁的是Class类模板,普通同步方法锁的是实例化的对象,
所以不用等待前者解锁后 后者才能执行,而是两者并行执行,因为发短信休眠4s
所以打电话先执行。
小结:
synchronized 锁的对象是方法的调用者
普通方法没有锁!不是同步方法,就不受锁的影响,正常执行
不同实例对象的Class类模板只有一个,static静态的同步方法,锁的是Class
此次八锁问题的说明就到这里了,欢迎小伙伴们留言讨论!