• synchronized关键字修饰非静态方法与静态方法的区别


    这里我们先创建ObjLock类,并实现Runnable接口。并创建一个Demo类,具有被synchronized关键字修饰的非静态方法与静态方法。

    非静态方法

    public class ObjLock implements Runnable {
    
        Demo demo;
    
        public ObjLock(Demo demo){
            this.demo = demo;
        }
    
        public void run() {
            demo.getI(Thread.currentThread().getName());
        }
    
        public static void main(String[] args){
            Demo demo = new Demo(1);
            Thread thread = new Thread(new ObjLock(demo),"thread0");
            Thread thread1 = new Thread(new ObjLock(demo),"thread1");
            Thread thread2 = new Thread(new ObjLock(new Demo(2)),"thread2");
            thread.start();
            thread1.start();
            thread2.start();
        }
    }
    
    
    class Demo{
    
        static int i;
    
        Demo(int i){
            this.i=i;
        }
    
        public static synchronized void staticGetI(String s){
            for (int j=0;j<10000;j++){
                System.out.println(i+"---------"+s);
            }
        }
    
        public synchronized void getI(String s){
            for (int j=0;j<10000;j++){
                System.out.println(i+"---------"+s);
            }
        }
    }

    运行程序,可以看到如下结果:

    1---------thread0
    1---------thread0
    2---------thread2
    1---------thread0
    2---------thread2
    1---------thread0
    1---------thread1
    1---------thread1
    2---------thread2
    1---------thread1
    1---------thread1
    1---------thread1

    可以看到Thread0和Thread2交替出现,Thread1和Thread2交替出现,但Thread0和Thread1不会交替出现。

    因为对非静态方法加锁,实际上是对调用该方法的对象加锁。Thread0和Thread1用的是同一个对象,所以互斥,但是Thread2则不受影响。

    静态方法

    将getI方法改成static之后

    public void run() {
        demo.staticGetI(Thread.currentThread().getName());
    }

    测试发现三个线程均互斥。

    当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class本身,注意:不是实例),作用范围是整个静态方法,作用的对象是这个类的所有对象。

    一个对象在两个线程中分别调用一个静态同步方法和一个非静态同步方法

    修改代码

    public void run() {
        if (Thread.currentThread().getName().equals("thread0")){
            demo.staticGetI(Thread.currentThread().getName());
        }else if (Thread.currentThread().getName().equals("thread1")){
            demo.getI(Thread.currentThread().getName());
        }
    } 

    结果:不会产生互斥。

    解释:因为虽然是一个对象调用,但是两个方法的锁类型不同,调用的静态方法实际上是类对象在调用,即这两个方法产生的并不是同一个对象锁,因此不会互斥,会并发执行。

  • 相关阅读:
    迁移-Mongodb时间类数据比较的坑
    Kong在windows10的hyperV CentOS上安装
    C#文件上传编码乱码
    入职9个月感想
    单元测试遇到的Mock重载方法问题
    MongoDB wiredTiger存储引擎下的存储方式LSM和B-Tree比较
    【SQL Server】修改DB逻辑文件名称
    【winform】基于UserControl实现webBrower组件时html页面元素加载及onclick事件监听实现
    SQL server 数据连接池使用情况检测
    【Vue起步-Windows】N01:环境安装
  • 原文地址:https://www.cnblogs.com/chongaizhen/p/10972747.html
Copyright © 2020-2023  润新知