前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >【JUC】002-8锁现象

【JUC】002-8锁现象

作者头像
訾博ZiBo
发布2025-01-06 16:40:48
发布2025-01-06 16:40:48
3400
代码可运行
举报
运行总次数:0
代码可运行

0、警醒自己

1、学习不用心,骗人又骗己;

2、学习不刻苦,纸上画老虎;

3、学习不惜时,终得人耻笑;

4、学习不复习,不如不学习;

5、学习不休息,毁眼伤身体;

7、狗才等着别人喂,狼都是自己寻找食物;

(问题回顾:什么是锁?到底锁的谁?要么锁new出来的对象,要么是Class,下面详解)

(8锁就是关于锁的8个问题)

一、问题1和2

1、问题

①标准情况下,两个线程是先打印发短信还是打电话?答:先发短信,后打电话;为什么?因为锁,详解见注释;

②让发短信方法睡4秒,是先发短信还是先打电话?答:还是先发短信,后打电话;为什么?因为锁,详解见注释;

2、代码、注释及运行结果

代码和注释:
代码语言:javascript
代码运行次数:0
运行
复制
package com.zibo.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁:关于锁的8个问题
 * 1、标准情况下,两个线程是先打印发短信还是打电话?答:先发短信,后打电话;为什么?因为锁,详解见注释
 * 2、让发短信方法睡4秒,是先发短信还是先打电话?答:还是先发短信,后打电话;为什么?因为锁,详解见注释
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        //两个线程,一个发短信,一个打电话
        new Thread(phone::sendSms,"A").start();
        //中间休息1s
        TimeUnit.SECONDS.sleep(1);
        new Thread(phone::call,"B").start();
    }
}
class Phone{

    //synchronized锁的对象是方法的调用者!
    //由于方法执行的时候拿到的是同一把锁,所以谁先拿到锁谁先执行
    public synchronized void sendSms() throws InterruptedException {
        //中间休息4s
        TimeUnit.SECONDS.sleep(4);
        System.out.println("发短信!");
    }

    public synchronized void call(){
        System.out.println("打电话!");
    }
}
运行结果:
代码语言:javascript
代码运行次数:0
运行
复制
发短信!
打电话!

3、答案再次说明

synchronized锁的对象是方法的调用者!由于方法执行的时候拿到的是同一把锁,所以谁先拿到锁谁先执行,无论发短信睡了多长时间,发短信没有释放锁,打电话都不会执行;

二、问题3

1、问题

A线程调用加了synchronized的发短信方法,B线程调用未加synchronized的hello方法,现在这种情况是先发短信,还是先say hello?

2、代码、注释及运行结果

代码和注释:
代码语言:javascript
代码运行次数:0
运行
复制
package com.zibo.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁:关于锁的8个问题
 * 3、A线程调用加了synchronized的发短信方法,B线程调用未加synchronized的hello方法,现在这种情况是先发短信,还是先say hello?答:先hello
 * 4、
 */
public class Test02 {
    public static void main(String[] args) throws InterruptedException {
        Phone02 phone = new Phone02();
        //两个线程,一个发短信,一个打电话
        new Thread(() -> {
            try {
                phone.sendSms();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        //中间休息1s
        TimeUnit.SECONDS.sleep(1);
        new Thread(phone::hello,"B").start();
    }
}

class Phone02{

    //synchronized锁的对象是方法的调用者!
    //由于方法执行的时候拿到的是同一把锁,所以谁先拿到锁谁先执行
    public synchronized void sendSms() throws InterruptedException {
        //中间休息4s
        TimeUnit.SECONDS.sleep(4);
        System.out.println("发短信!");
    }

    public synchronized void call(){
        System.out.println("打电话!");
    }

    //答案解析:先hello,因为hello这里没锁,发短信把锁拿走了,不管hello什么事
    public void hello(){
        System.out.println("say hello!");
    }
}
运行结果:
代码语言:javascript
代码运行次数:0
运行
复制
say hello!
发短信!

3、答案再次说明

先hello,因为hello这里没锁,发短信把锁拿走了,不管hello什么事;

三、问题4

1、问题

使用两个对象,调用发短信和打电话,谁先执行?

2、代码、注释及运行结果

代码和注释:
代码语言:javascript
代码运行次数:0
运行
复制
package com.zibo.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁:关于锁的8个问题
 * 3、A线程调用加了synchronized的发短信方法,B线程调用未加synchronized的hello方法,现在这种情况是先发短信,还是先say hello?答:先hello
 * 4、使用两个对象,调用发短信和打电话,谁先执行?答:先打电话,后发短信;
 */
public class Test02 {
    public static void main(String[] args) throws InterruptedException {
        //使用两个对象,调用发短信和打电话,谁先执行?
        Phone02 phone1 = new Phone02();
        Phone02 phone2 = new Phone02();
        //两个线程,一个发短信,一个打电话
        new Thread(() -> {
            try {
                phone1.sendSms();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        //中间休息1s
        TimeUnit.SECONDS.sleep(1);
        new Thread(phone2::call,"B").start();
    }
}

class Phone02{

    //synchronized锁的对象是方法的调用者!
    //由于方法执行的时候拿到的是同一把锁,所以谁先拿到锁谁先执行
    public synchronized void sendSms() throws InterruptedException {
        //中间休息4s
        TimeUnit.SECONDS.sleep(4);
        System.out.println("发短信!");
    }

    //使用两个对象,谁先执行?答:先打电话,后发短信;
    //因为不同的锁,锁的是不同的对象,相互没有关系,这个时候就看先执行到到哪句打印语句了
    //发短信睡了4秒,显然先执行到打电话
    public synchronized void call(){
        System.out.println("打电话!");
    }

    //答案解析:先hello,因为hello这里没锁,发短信把锁拿走了,不管hello什么事
    public void hello(){
        System.out.println("say hello!");
    }
}
运行结果:
代码语言:javascript
代码运行次数:0
运行
复制
打电话!
发短信!

3、答案再次说明

使用两个对象,谁先执行?答:先打电话,后发短信; 因为不同的锁对象,相互没有关系,这个时候就看先执行到到哪句打印语句了,发短信睡了4秒,显然先执行到打电话;

四、问题5

1、问题

增加两个静态的同步方法,是先发短信还是先打电话?

2、代码、注释及运行结果

代码和注释:
代码语言:javascript
代码运行次数:0
运行
复制
package com.zibo.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁:关于锁的8个问题
 * 5、增加两个静态的同步方法,是先发短信还是先打电话?答:先发短信
 */
public class Test03 {
    public static void main(String[] args) throws InterruptedException {
        //两个线程,一个发短信,一个打电话
        new Thread(() -> {
            try {
                Phone03.sendSms();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        //中间休息1s
        TimeUnit.SECONDS.sleep(1);
        new Thread(Phone03::call,"B").start();
    }
}

class Phone03{

    //synchronized锁的对象是方法的调用者!静态方法锁的是类
    //static方法,类已加载就有了,锁的是class类文件,Phone03只有唯一的一个class类文件
    //由于方法执行的时候拿到的是同一把锁,所以谁先拿到锁谁先执行
    //Class<Phone03> phone03Class = Phone03.class;//这个class是全局唯一的,static锁的就是这个对象
    public static synchronized void sendSms() throws InterruptedException {
        //中间休息4s
        TimeUnit.SECONDS.sleep(4);
        System.out.println("发短信!");
    }


    public static synchronized void call(){
        System.out.println("打电话!");
    }
}
运行结果:
代码语言:javascript
代码运行次数:0
运行
复制
发短信!
打电话!

3、答案再次说明

synchronized锁的对象是方法的调用者!静态方法锁的是类;

static方法,类已加载就有了,锁的是class类文件,Phone03这个类只有唯一的一个class类文件;

Class<Phone03> phone03Class = Phone03.class;//这个class是全局唯一的,static锁的就是这个对象;

由于方法执行的时候拿到的是同一把锁,所以谁先拿到锁谁先执行;

五、问题6

1、问题

使用两个Phone04的对象进行调用静态方法,是先发短信还是先打电话?

2、代码、注释及运行结果

代码及注释:
代码语言:javascript
代码运行次数:0
运行
复制
package com.zibo.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁:关于锁的8个问题
 * 5、增加两个静态的同步方法,是先发短信还是先打电话?答:先发短信
 * 6、使用两个Phone04的对象进行调用静态方法,是先发短信还是先打电话?答:还是先发短信
 * 静态方法锁的是类,与对象无关!
 */
public class Test04 {
    public static void main(String[] args) throws InterruptedException {
        //使用两个Phone04的对象进行调用静态方法
        //答案解析:静态方法锁的是类,与对象无关!
        Phone04 phone1 = new Phone04();
        Phone04 phone2 = new Phone04();
        //两个线程,一个发短信,一个打电话
        new Thread(() -> {
            try {
                phone1.sendSms();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        //中间休息1s
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> phone2.call(),"B").start();
    }
}

class Phone04{

    //synchronized锁的对象是方法的调用者!静态方法锁的是类
    //static方法,类已加载就有了,锁的是class类文件,Phone03只有唯一的一个class类文件
    //由于方法执行的时候拿到的是同一把锁,所以谁先拿到锁谁先执行
    //Class<Phone03> phone03Class = Phone03.class;//这个class是全局唯一的,static锁的就是这个对象
    public static synchronized void sendSms() throws InterruptedException {
        //中间休息4s
        TimeUnit.SECONDS.sleep(4);
        System.out.println("发短信!");
    }


    public static synchronized void call(){
        System.out.println("打电话!");
    }
}
运行结果:
代码语言:javascript
代码运行次数:0
运行
复制
发短信!
打电话!

3、答案再次说明

静态方法锁的是类,与对象无关!

6、问题7和8

1、问题

一个静态同步方法、一个普通同步方法,一个对象调用,是先发短信还是先打电话?

一个静态同步方法、一个普通同步方法,两个对象调用,是先发短信还是先打电话?

2、代码、注释及运行结果

代码及注释:
代码语言:javascript
代码运行次数:0
运行
复制
package com.zibo.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8锁:关于锁的8个问题
 * 7、一个静态同步方法、一个普通同步方法,一个对象调用,是先发短信还是先打电话?答:先打电话!
 * 为什么先打电话呢?因为静态方法锁的是Phone05类,普通方法锁的是phone对象,两把锁,互不影响,发短信睡眠4s,打电话肯定先执行完;
 * 8、一个静态同步方法、一个普通同步方法,两个对象调用,是先发短信还是先打电话?答:先打电话!
 * (非常简单易懂,代码里面就不体现了)
 * 为什么先打电话呢?道理是一样的!两把锁,互不影响!
 */
public class Test05 {
    public static void main(String[] args) throws InterruptedException {
        //使用两个Phone04的对象进行调用静态方法
        //答案解析:静态方法锁的是类,与对象无关!
        Phone05 phone = new Phone05();
        //两个线程,一个发短信,一个打电话
        new Thread(() -> {
            try {
                phone.sendSms();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        //中间休息1s
        TimeUnit.SECONDS.sleep(1);
        new Thread(phone::call,"B").start();
    }
}

class Phone05{

    //静态同步方法
    public static synchronized void sendSms() throws InterruptedException {
        //中间休息4s
        TimeUnit.SECONDS.sleep(4);
        System.out.println("发短信!");
    }

    //普通同步方法
    public synchronized void call(){
        System.out.println("打电话!");
    }
}
运行结果:
代码语言:javascript
代码运行次数:0
运行
复制
打电话!
发短信!

3、答案再次说明

因为静态方法锁的是Phone05类,普通方法锁的是phone对象,两把锁,互不影响,发短信睡眠4s,打电话肯定先执行完;

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0、警醒自己
  • 一、问题1和2
    • 1、问题
    • 2、代码、注释及运行结果
      • 代码和注释:
      • 运行结果:
    • 3、答案再次说明
  • 二、问题3
    • 1、问题
    • 2、代码、注释及运行结果
      • 代码和注释:
      • 运行结果:
    • 3、答案再次说明
  • 三、问题4
    • 1、问题
    • 2、代码、注释及运行结果
      • 代码和注释:
      • 运行结果:
    • 3、答案再次说明
  • 四、问题5
    • 1、问题
    • 2、代码、注释及运行结果
      • 代码和注释:
      • 运行结果:
    • 3、答案再次说明
  • 五、问题6
    • 1、问题
    • 2、代码、注释及运行结果
      • 代码及注释:
      • 运行结果:
    • 3、答案再次说明
  • 6、问题7和8
    • 1、问题
    • 2、代码、注释及运行结果
      • 代码及注释:
      • 运行结果:
    • 3、答案再次说明
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档