说说自己是怎么使用 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对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值