synchronized修饰静态方法和普通方法的区别

在Java中,synchronized关键字用于控制对共享资源的并发访问,以防止多个线程同时修改共享资源而导致数据不一致的问题。synchronized可以修饰方法或代码块,而当它修饰方法时,可以应用于静态方法和普通(实例)方法。这两者有一些关键的区别:

  1. 锁定对象不同
    普通方法(实例方法):当synchronized修饰普通方法时,它锁定的是调用该方法的对象实例。也就是说,当一个线程进入这个方法的同步代码块时,其他试图进入这个实例的任何synchronized实例方法的线程都会被阻塞,直到锁被释放。
    静态方法:当synchronized修饰静态方法时,它锁定的是调用该方法的类的Class对象。这意味着,当一个线程进入这个静态方法的同步代码块时,其他试图进入同一个类的任何synchronized静态方法的线程都会被阻塞,直到锁被释放。此外,由于静态方法属于类级别,因此所有实例共享这个锁。

  2. 访问控制范围不同
    普通方法:由于锁的是实例对象,因此synchronized实例方法控制的并发访问是针对具体对象的。不同的对象实例可以有不同的锁,互不干扰。
    静态方法:由于锁的是Class对象,synchronized静态方法控制的并发访问是针对整个类的。所有实例共享这个锁,因此当一个实例调用静态同步方法时,其他实例不能同时调用同一个类的任何静态同步方法。

  3. 使用场景
    普通方法:适用于保护实例变量的并发访问。
    静态方法:适用于保护静态变量的并发访问,或需要确保类的全局行为一致性(如单例模式的实现)。
    示例
    java
    public class Example {
    private int instanceVar = 0;
    private static int staticVar = 0;

    // Synchronized instance method
    public synchronized void incrementInstanceVar() {
    instanceVar++;
    }

    // Synchronized static method
    public static synchronized void incrementStaticVar() {
    staticVar++;
    }

    public static void main(String[] args) {
    Example ex1 = new Example();
    Example ex2 = new Example();

     // Different locks for instance methods  
     new Thread(() -> {  
         for (int i = 0; i < 1000; i++) {  
             ex1.incrementInstanceVar();  
         }  
     }).start();  
    
     new Thread(() -> {  
         for (int i = 0; i < 1000; i++) {  
             ex2.incrementInstanceVar();  
         }  
     }).start();  
    
     // Same lock for static methods  
     new Thread(() -> {  
         for (int i = 0; i < 1000; i++) {  
             Example.incrementStaticVar();  
         }  
     }).start();  
    
     new Thread(() -> {  
         for (int i = 0; i < 1000; i++) {  
             Example.incrementStaticVar();  
         }  
     }).start();  
    
     // Let the threads run  
     try {  
         Thread.sleep(1000);  
     } catch (InterruptedException e) {  
         e.printStackTrace();  
     }  
    
     System.out.println("Instance variable: " + ex1.instanceVar + " (should be close to 2000)");  
     System.out.println("Static variable: " + Example.staticVar + " (should be close to 2000)");  
    

    }
    }
    在这个例子中,两个线程可以并发地调用incrementInstanceVar方法,因为每个线程操作的是不同的Example实例,所以它们不会互相阻塞。然而,两个线程不能并发地调用incrementStaticVar方法,因为它们都试图锁定同一个Class对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值