synchronized关键字锁住的是对象还是代码块

本文通过三个示例详细解析了Java中synchronized关键字的使用方法及其对对象加锁的行为。演示了如何通过静态方法、实例方法及指定对象实现同步,同时展示了不同锁对象对线程同步的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

synchronized 修饰的是对象,而不是代码块。测试代码来自于博客http://www.cnblogs.com/QQParadise/articles/5059824.html
下面两端代码都可以正常显示执行结果:

test开始..
test结束..
test开始..
test结束..
test开始..
test结束..

第一段代码锁住了Sync这个类对象(取决于static关键字),而第二段也是锁住了Sync这个类对象,取决于synchronize(clock)中的clock。而第三段代码执行结果就是错误的,因为每次都锁住了新建的对象。

class Sync {  

    public static synchronized void test() {  
        //synchronized (Sync.class) {  
            System.out.println("test开始..");  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            System.out.println("test结束..");  
        //}  
    }  
}  

class MyThread extends Thread {  

    public void run() {  
        Sync sync = new Sync();  
        sync.test();  
    }  
}  

public class Main {  

    public static void main(String[] args) {  
        for (int i = 0; i < 3; i++) {  
            Thread thread = new MyThread();  
            thread.start();  
        }  
    }  
}  
class Sync {  

    public void test() {  
        synchronized (Sync.class) {  
            System.out.println("test开始..");  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            System.out.println("test结束..");  
        }  
    }  
}  

class MyThread extends Thread {  

    public void run() {  
        Sync sync = new Sync();  
        sync.test();  
    }  
}  

public class Main {  

    public static void main(String[] args) {  
        for (int i = 0; i < 3; i++) {  
            Thread thread = new MyThread();  
            thread.start();  
        }  
    }  
}  
class Sync {  

    public synchronized  void test() {  
        //synchronized (Sync.class) {  
            System.out.println("test开始..");  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            System.out.println("test结束..");  
        //}  
    }  
}  

class MyThread extends Thread {  

    public void run() {  
        Sync sync = new Sync();  
        sync.test();  
    }  
}  

public class Main {  

    public static void main(String[] args) {  
        for (int i = 0; i < 3; i++) {  
            Thread thread = new MyThread();  
            thread.start();  
        }  
    }  
}  
<think>好的,我现在需要回答用户关于Java中synchronized关键字修饰方法和修饰代码块的区别的问题。首先,我得确认自己对这方面的知识掌握程度,如果有不确定的地方,可能需要查阅资料来确保回答的准确性。 用户之前询问过如何使用Lambda表达式为TreeSet设置Comparator,现在转向了多线程同步的问题,看来用户在学习Java的不同方面。我需要用清晰的结构来解释两者的区别,可能包括定义、使用方式、锁对象、粒度控制、性能影响等方面。 首先,回顾synchronized的基本概念。synchronized用于实现线程同步,确保多个线程在访问共享资源时的正确性。修饰方法和代码块都是实现同步的方式,但具体实现上有差异。 接下来,区分修饰方法和代码块的不同点: 1. **修饰方法**: - 实例方法:锁的是当前实例对象(this)。 - 静态方法:锁的是当前类的Class对象。 - 整个方法体都是同步的,可能影响性能,尤其是在方法体较大或执行时间较长时。 2. **修饰代码块**: - 需要显式指定锁对象,可以是任意对象实例或类对象。 - 只同步代码块内的代码,其他代码可以并发执行,提高了灵活性,减少锁的持有时间,提升性能。 然后,考虑用户可能的疑惑点,比如锁的对象是什么,为什么选择代码块而不是方法,或者相反。需要举例说明,比如使用不同的锁对象可能导致不同的同步效果,或者如何避免死锁等。 还要注意,是否需要提到其他相关概念,比如可重入锁、锁的粒度、以及synchronized在JVM中的实现(如monitor enter和exit)?不过用户的问题比较基础,可能不需要深入到JVM层面,但简要提及锁的粒度对性能的影响是有必要的。 另外,可能存在的误区需要澄清,比如是否所有方法都需要同步,或者过度同步导致的性能问题。例如,在实例方法上加synchronized,如果多个线程操作不同的实例,并不会互斥,而静态方法则会锁住整个类,所有实例的访问都会同步。 最后,总结两者的适用场景,帮助用户根据具体情况选择使用方式。例如,代码块适合需要更细粒度控制的场景,而修饰方法则代码更简洁,适合整个方法都需要同步的情况。 在组织回答时,按照用户要求的“结构清晰,逐步解决问题”,可能需要分点列出区别,并给出代码示例,说明各自的使用场景和注意事项。同时,确保语言简洁明了,避免技术术语过多,必要时进行解释。 现在需要验证一下自己的理解是否正确: - 修饰实例方法时,锁是对象实例;修饰静态方法时,锁是类对象。而代码块需要指定锁对象,可以是任意对象,比如某个实例变量或者类变量。 - 代码块允许更细粒度的控制,比如在方法内部只有部分代码需要同步,其余部分可以异步执行,从而减少线程阻塞时间,提高效率。 - 正确的示例代码,比如同步方法对比同步代码块,展示不同的锁对象使用方式。 可能还需要提到,使用代码块时,可以选择更小的锁范围,减少竞争,提高并发性能。比如,如果同步方法中的某些代码不需要同步,那么使用代码块可以避免不必要的等待。 总结之后,确保回答覆盖了用户的问题,没有遗漏关键点,并且示例代码正确无误,能够帮助用户理解两者的区别。</think>在Java中,`synchronized`关键字修饰方法和修饰代码块的主要区别体现在**锁的范围**、**灵活性**和**性能优化**等方面。以下是具体对比: --- ### 一、修饰方法(Method Level) #### 1. 语法格式 ```java // 实例方法 public synchronized void method() { // 方法体 } // 静态方法 public static synchronized void staticMethod() { // 方法体 } ``` #### 2. 核心特点 - **锁对象**: - 实例方法:锁是当前对象实例(`this`)。 - 静态方法:锁是类的`Class`对象(如`MyClass.class`)。 - **同步范围**:整个方法体被同步。 - **适用场景**:简单场景,方法整体需要同步。 #### 3. 示例 ```java public class Counter { private int count = 0; // 实例方法同步(锁this) public synchronized void increment() { count++; } // 静态方法同步(锁Counter.class) public static synchronized void log() { System.out.println("Static method"); } } ``` --- ### 二、修饰代码块(Block Level) #### 1. 语法格式 ```java public void method() { // 非同步代码 synchronized (lockObject) { // 需要同步的代码块 } // 其他代码 } ``` #### 2. 核心特点 - **锁对象**:可自由指定(如`this`、任意对象实例或`Class`对象)。 - **同步范围**:仅代码块内的逻辑被同步。 - **灵活性**:可缩小锁的粒度,减少线程阻塞时间。 - **适用场景**:需要精细控制同步范围,或使用非`this`锁的情况。 #### 3. 示例 ```java public class Counter { private int count = 0; private final Object lock = new Object(); // 自定义锁对象 public void increment() { // 非同步代码(可并发执行) synchronized (lock) { // 仅同步关键操作 count++; } // 其他非同步代码 } } ``` --- ### 三、关键区别总结 | **对比维度** | **修饰方法** | **修饰代码块** | |--------------------|--------------------------------------|-------------------------------------| | **锁对象** | 隐式:实例方法锁`this`,静态方法锁`Class` | 显式:可指定任意对象 | | **同步范围** | 整个方法体 | 仅代码块内部 | | **性能** | 可能较差(锁持有时间长) | 更优(减少锁占用时间) | | **灵活性** | 低 | 高(可自由控制锁范围和对象) | | **代码可读性** | 简单直接 | 需要明确锁对象和范围 | --- ### 四、使用建议 1. **优先选择代码块**: 当只有部分代码需要同步时,使用代码块缩小锁范围,提升并发性能。 2. **避免锁冲突**: 若需同步多个无关资源,应为不同资源定义独立的锁对象,避免全局锁竞争。 3. **静态方法慎用**: 静态方法的锁是类级别的,所有实例共享同一锁,可能导致意外阻塞。 --- ### 五、典型场景示例 #### 场景1:缩小锁粒度(提高性能) ```java public class DatabaseService { private List<String> cache = new ArrayList<>(); private final Object cacheLock = new Object(); // 缓存专用锁 public void updateCache(String data) { // 非同步代码(如数据预处理) synchronized (cacheLock) { // 仅同步缓存更新操作 cache.add(data); } } } ``` #### 场景2:避免全局锁(减少竞争) ```java public class BankAccount { private int balance; private final Object balanceLock = new Object(); // 独立锁 public void transfer(BankAccount target, int amount) { // 同步代码块:分别锁定当前账户和目标账户 synchronized (this.balanceLock) { synchronized (target.balanceLock) { this.balance -= amount; target.balance += amount; } } } } ``` --- 通过合理选择同步方式,可以平衡线程安全与性能需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值