zoukankan      html  css  js  c++  java
  • synchronized修饰类中不同方法,调用的时候方法互斥吗

    我们知道,使用synchronized关键字修饰方法时,多个线程调用此方法,会互斥执行。如果synchronized修饰不同的方法,多个线程再分别调用这些方法时是互斥的吗?下面使用代码模拟一下:

    新建一个User类:

    public class User {
    
        public synchronized void getUp() {
            System.out.println("起床...");
            try {
                TimeUnit.SECONDS.sleep(2L); // 暂停2s
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public synchronized void eatBreakfast() {
            System.out.println("吃早餐...");
        }
    }
    

    User类中,两个方法都使用synchronized关键字修饰了,写一个测试方法测试一下:

    注意:Junit单元测试时,当主线程结束后,不管子线程是否结束都会退出,所以这里使用CountDownLatch,让主线阻塞等待子线程运行完成。

    	@Test
        public void test1() {
            CountDownLatch latch = new CountDownLatch(2);
            User user = new User(); // 创建user对象
            User user2 = new User(); // 创建user2对象
            new Thread(() -> {
                user.getUp();
                latch.countDown();
            }).start();
            try {
                TimeUnit.SECONDS.sleep(1L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                user2.eatBreakfast();
                latch.countDown();
            }).start();
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    

    运行结果:

    起床...
    吃早餐...
    

    可以看到,创建两个对象调用不同的synchronized修饰的方法的时候,并没有出现互斥访问的情况,eatBreakfast方法并没有等待getUp方法执行完毕再执行,原因也很简单,这两个方法获取的不是同一个锁对象。

    修改测试方法,改成一个对象来访问不同的synchronized修饰的方法:

    	@Test
        public void test2() {
            CountDownLatch latch = new CountDownLatch(2);
            User user = new User(); // 创建user对象
            new Thread(() -> {
                user.getUp();
                latch.countDown();
            }).start();
            try {
                TimeUnit.SECONDS.sleep(1L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                user.eatBreakfast();
                latch.countDown();
            }).start();
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    

    运行结果:

    起床...
    吃早餐...
    

    可以看到,方法是顺序执行的,也就是互斥访问的,getUp方法中,使用TimeUnit.SECONDS.sleep(2L)让方法延迟了2s,然后在测试方法中延迟1s调用eatBreakfast方法,如果方法不是互斥访问的,应该是eatBreakfast先执行,为了看清效果,你可以让getUp方法延迟更久,看一下是不是还是要等getUp方法执行完毕再执行eatBreakfast方法。

    这说明,synchronized锁的对象是调用者,这两个方法用的是同一把锁,谁先拿到,谁先执行,执行完毕释放锁以后,下一个方法获取锁才执行,而不是谁先被调用就一定先被执行。同理static synchronized修饰的静态同步方法也是类似的,由于锁是字节码文件对象,调用是也是互斥的,谁先获取锁谁就先被执行。

    一颗安安静静的小韭菜。文中如果有什么错误,欢迎指出。
  • 相关阅读:
    java编码过滤器
    DAO设计模式
    常用的SQL语句
    IO流总结
    IO流的登录与注册
    设计模式之模板方法模式(Template Method)详解及代码示例
    设计模式之享元模式(Flyweight)详解及代码示例
    设计模式之桥接模式(Bridge)详解及代码示例
    设计模式之组合模式(Composite)详解及代码示例
    设计模式之外观模式(Facade)详解及代码示例
  • 原文地址:https://www.cnblogs.com/c-Ajing/p/13448343.html
Copyright © 2011-2022 走看看