JUC多线程编程八锁你都知道了吗?关于锁的八个问题

news/2024/5/20 7:24:01 标签: 多线程, 并发编程, java, juc,

关于的八个问题—八

前面的文章中留下一个疑问,到底什么是到底的是谁?
这里我们就用打电话和发短信的例子来距离说明八问题—>的是对象方法的调用者或者Class模板(.class)

1、标准情况下,两个线程先打印 发短信还是 先打印 打电话?

java">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秒,两个线程先打印 发短信还是 打电话?

java">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?

java">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、 两个对象,两个同步方法, 发短信还是 打电话?

java">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、增加两个静态的同步方法,只有一个对象,先打印 发短信?打电话?

java">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、两个对象!增加两个静态的同步方法, 先打印 发短信?打电话?

java">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个普通的同步方法 ,一个对象,先打印 发短信?打电话?

java">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个普通的同步方法 ,两个对象,先打印 发短信?打电话?

java">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

此次八问题的说明就到这里了,欢迎小伙伴们留言讨论!


http://www.niftyadmin.cn/n/1715665.html

相关文章

使用宝塔部署node项目_宝塔面板如何部署nuxt项目

1、先在本地执行npm run build 命令,然后将项目根目录下除了node_modules文件夹,其他都打包上传到服务器web服务下,注意.nuxt是隐藏文件夹。当然其实不build也可以,在服务上执行sudo npm install 后再执行 run build也一样。然后执…

写入时复制原理和过程以及CopyOnWriteArrayList源码实现的深入剖析

问题疑问 1.为什么要叫写入时复制集合? 2.CopyOnWriteArrayList 实现原理是什么? 3.CopyOnWriteArrayList 和 ArrayList 有什么区别? 4.CopyOnWriteArrayList 复制是怎么进行复制的? 接下来就让我们带着这几个问题,从…

走进callable,来看看callable是怎么一步步勾搭上Thread的!

1.Callable接口 2.Callable与Runnable不同 *1.Callable是java.util.concurrent下的接口,有返回值,可以跑出被检查出的异常 *2Runable是java.lang下的接口,没有返回值,不可以抛出检查出的异常 *3.二者重写调用的方法不同&#xf…

sublime编译python乱码_Sublime Text 3使用virtualenv插件编译时编译结果乱码的问题解决方案...

使用sublime text 3编写python脚本时,平常使用CtrlB的编译系统编译在输出结果中中文就是显示正确的中文,不会显示乱码,但是当我启用了virtualenv插件,使用虚拟环境编译时,却看到中文显示出了乱码。我又在cmd运行python…

JUC的三大常用辅助类,你都知道吗?

1.countDownLatch 减法计数器:实现调用几次线程后,在触发另一个任务 简单代码实现: *举例说明:就像五个人在同一房间里,有一个看门的大爷,当五个人都出去后,他才能锁门,也就是说 执…

ReadWriteLock,读写锁你真的会用吗?

ReadWriteLock 基本介绍 独占锁(写锁) 一次只能被一个线程占有共享锁(读锁) 多个线程可以同时占有 ReadWriteLock 读-读 可以共存!读-写 不能共存!写-写 不能共存!可以多个线程同时读&#…

事务的隔离级别举例_一文彻底读懂MySQL事务的四大隔离级别

前言之前分析一个死锁问题,发现自己对数据库隔离级别理解还不够深入,所以趁着这几天假期,整理一下MySQL事务的四大隔离级别相关知识,希望对大家有帮助~事务什么是事务?事务,由一个有限的数据库操作序列构成…

全是干货---阻塞队列BlockingQueue+BlockingQueue四组API+同步队列SynchronousQueue

1.阻塞队列BlockingQueue 简单介绍: 其实呐,阻塞队列也不是什么比较新的东西,他也是collection下的一种,与set、list等是同一等级的 那什么情况下,在哪种场景下我们会使用到阻塞队列呢? *多线程并发处…