说说自己是怎么使用 synchronized 关键字?

使用 synchronized 关键字的方法主要有两种:同步方法和同步代码块。

1. 同步方法

同步方法是最简单的使用方式。当你声明一个方法为 synchronized 时,Java 虚拟机确保在同一时刻,只有一个线程可以执行该方法。如果这个方法是一个实例方法,它锁定的是调用该方法的对象;如果是静态方法,则锁定的是这个类的 Class 对象。

public class Counter {
    private int count = 0;

    // 同步实例方法
    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

在这个示例中,increment() 和 getCount() 都是同步的,所以它们不能被同一对象的两个线程同时访问。

public class Utils {
    private static int value = 0;

    // 同步静态方法
    public static synchronized void addValue(int add) {
        value += add;
    }
}

这里的 addValue() 是一个静态同步方法,锁定的是 Utils.class 这个类对象,确保同一时间只有一个线程可以执行这个方法。

2. 同步代码块

同步代码块用于同步方法中的一部分代码,而不是整个方法。这可以减少等待时间,提高效率。同步代码块需要指定一个锁对象。

public class App {
    private final Object lock = new Object();
    private List<String> names = new ArrayList<>();

    public void addName(String name) {
        synchronized(lock) {
            names.add(name);
        }
    }
}

在这个示例中,只有添加名称到列表的部分是同步的。通过使用锁对象,我们可以更细粒度地控制同步,而不是锁定整个方法。

使用技巧和注意事项

  • 最小锁定范围:尽量只在必要的范围内使用同步,以避免性能损失。
  • 避免死锁:确保多个线程不会因为相互等待对方持有的锁而陷入停滞。
  • 选择合适的锁对象:在使用同步代码块时,选择适当的对象作为锁,避免使用字符串常量或全局对象作为锁,以减少意外的锁冲突。

实例方法上的synchronized:

  • 当一个实例方法被synchronized修饰时,线程在调用该方法之前,需要获得当前实例对象的锁(即this)。
  • 如果一个线程已经持有该对象的锁,其他线程将无法调用任何被synchronized修饰的实例方法,直到该锁被释放。
  • 锁定的范围是具体的实例,即不同实例的synchronized实例方法可以并发执行,因为它们锁定的是不同的对象。
public synchronized void instanceMethod() {
    // method implementation
}

静态方法上的synchronized:

  • 当一个静态方法被synchronized修饰时,线程在调用该方法之前,需要获得该类的Class对象的锁(即ClassName.class)。
  • 如果一个线程已经持有该类的Class对象的锁,其他线程将无法调用任何被synchronized修饰的静态方法,直到该锁被释放。
  • 锁定的范围是整个类,即无论多少实例存在,所有实例共享同一个Class对象的锁。
public static synchronized void staticMethod() {
    // method implementation
}

区别总结

锁定对象的范围:

  • 实例方法锁定的是调用该方法的具体实例对象。不同实例之间互不影响。
  • 静态方法锁定的是整个类的Class对象,即所有实例共享这一个锁。

并发控制粒度:

  • 实例方法提供的是对象级别的锁,粒度较细,可以允许多个实例并行执行各自的synchronized实例方法。
  • 静态方法提供的是类级别的锁,粒度较粗,只要有一个线程在执行被锁定的静态方法,其他线程无论是访问同一个静态方法还是其他被synchronized修饰的静态方法,都将被阻塞。

实例方法锁定示例:

public class MyClass {
    public synchronized void instanceMethod() {
        // 仅锁定当前实例对象
    }
}

MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
Thread t1 = new Thread(() -> obj1.instanceMethod());
Thread t2 = new Thread(() -> obj2.instanceMethod());
t1.start();
t2.start(); // t1和t2可以并行执行,因为锁定的是不同的对象

静态方法锁定示例:

public class MyClass {
    public static synchronized void staticMethod() {
        // 锁定整个类的Class对象
    }
}

Thread t1 = new Thread(() -> MyClass.staticMethod());
Thread t2 = new Thread(() -> MyClass.staticMethod());
t1.start();
t2.start(); // t1和t2无法并行执行,因为锁定的是同一个Class对象
  • 16
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: SynchronizedJava提供的一种机制,可以保证代码块或者方法在同一时刻只能被一个线程执行。可以应用在多线程并发访问共享资源的场景中,保证数据的正确性和一致性。当一个线程获得了Synchronized关键字的锁后,其他线程必须等待该线程释放该锁之后才能获得该锁进行访问。 ### 回答2: SynchronizedJava语言中的关键字,用于实现多个线程之间的同步操作。当一个方法或代码块被synchronized修饰时,表示在同一时刻最多只能有一个线程执行该方法或代码块。 使用synchronized可以解决多线程并发访问共享资源时可能出现的数据不一致问题。当多个线程同时访问某个共享资源时,使用synchronized可以确保每个线程按照一定的顺序进行访问,避免出现数据冲突的情况。 synchronized可以修饰方法、代码块或静态方法。当修饰方法时,锁住的是当前对象;当修饰代码块时,锁住的是括号中指定的对象;当修饰静态方法时,锁住的是当前类的Class对象。 当一个线程执行到一个synchronized方法或代码块时,会尝试获得锁。如果锁已被其他线程占用,则该线程会进入阻塞状态,直到获取到锁后才能继续执行。在synchronized方法或代码块执行完毕后,会自动释放锁,其他线程可以继续竞争获取锁。 虽然synchronized确保了多线程间的互斥访问共享资源,但也会导致性能下降。因为当一个线程持有锁时,其他线程无法并行执行,需要等待锁释放后才能执行。因此,在使用synchronized时,应尽量减小锁的粒度,只锁住必要的代码块,避免不必要的性能损耗。 除了synchronized关键字Java还提供了Lock接口及其实现类ReentrantLock来实现线程间的同步。相比之下,Lock提供了更加细粒度的锁控制,更加灵活和可扩展。但在实际开发中,synchronized已经能够满足大部分需求,使用synchronized更加简单和方便。 ### 回答3: Synchronized关键字Java中用于实现线程同步的关键字。当一个方法或代码块被Synchronized关键字修饰时,他们在同一时间只能被一个线程访问,其他线程需要等待。 Synchronized关键字可以应用于两种情况:在方法声明中作为修饰符,或者在代码块中使用。当应用于方法中时,Synchronized关键字将整个方法包括在同步区域内,只允许一个线程访问该方法。当应用于代码块中时,Synchronized关键字将只同步代码块中的内容,只允许一个线程进入该代码块,其他线程需要等待。 Synchronized关键字使用可以有效解决多线程环境下的数据竞争和资源冲突问题。当多个线程同时访问共享的数据或资源时,可能会导致数据不一致或逻辑错误。Synchronized关键字能够保证同一时间只有一个线程访问共享资源,避免发生竞争条件。 然而,Synchronized关键字也具有一些限制。首先,使用Synchronized关键字会导致性能下降,因为其他线程需要等待。其次,Synchronized关键字只能保证同一时间只有一个线程访问共享资源,但不能保证访问的顺序。最后,Synchronized关键字只能在同一个JVM中的不同线程之间实现同步,无法对多个JVM或分布式环境中的线程进行同步。 总之,Synchronized关键字Java中用于实现线程同步的关键字,它可以避免多线程环境下的数据竞争和资源冲突问题。然而,它也有一些限制,包括性能下降、无法保证访问顺序以及无法在分布式环境中使用。在使用Synchronized关键字时,需要根据实际情况选择合适的同步方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值