synchronized 关键字作为同步锁时有哪些用法?请举例说明。
参考回答
synchronized
关键字是 Java 提供的一种内置同步机制,用于解决多线程环境下的线程安全问题。它可以用来修饰方法或代码块,保证同一时间只有一个线程可以访问被同步的代码。
synchronized
的主要用法包括:
- 修饰实例方法:对当前实例对象加锁。
- 修饰静态方法:对类对象加锁。
- 修饰代码块:对指定对象加锁。
详细讲解与示例
1. 修饰实例方法
作用:
- 同步方法对当前实例对象加锁,多个线程访问同一实例的同步方法时会发生互斥。
示例:
输出(线程互斥执行):
线程1 开始执行
线程1 执行结束
线程2 开始执行
线程2 执行结束
特点:
syncMethod()
方法锁住的是当前实例对象obj
,同一时间只有一个线程可以执行方法。
2. 修饰静态方法
作用:
- 同步静态方法对类对象(
Class
)加锁,无论多少线程访问该类的实例,静态方法都只能被一个线程访问。
示例:
输出(静态方法锁类对象):
线程1 开始执行
线程1 执行结束
线程2 开始执行
线程2 执行结束
特点:
syncStaticMethod()
方法锁住的是类对象SynchronizedStaticMethod.class
。- 无论是否使用同一实例调用静态方法,线程都会互斥。
3. 修饰代码块
作用:
synchronized
代码块对指定的对象加锁,而不是方法或类。灵活性更高,可用于精确控制锁的范围。
示例:
输出(代码块锁对象):
线程1 尝试进入同步块
线程1 开始执行同步块
线程1 执行结束
线程2 尝试进入同步块
线程2 开始执行同步块
线程2 执行结束
特点:
- 只对指定的代码块加锁,锁住的对象是
lock
,线程必须持有lock
的锁才能进入同步块。 - 相比同步方法,锁的粒度更小,性能更高。
注意事项
- 对象锁与类锁不同
- 实例方法加锁(
synchronized
修饰实例方法)锁的是当前对象实例。 - 静态方法加锁(
synchronized
修饰静态方法)锁的是类对象。 - 两者互不影响。
- 实例方法加锁(
示例:
输出:
- 实例方法和静态方法分别锁住不同对象,可以并发执行:
线程1 执行实例方法
线程2 执行静态方法
- 避免死锁
- 当多个线程同时请求多个锁时,可能会导致死锁。需要保证加锁顺序一致。
示例(容易死锁):
总结
synchronized
关键字的用法:
- 修饰实例方法:锁住当前实例对象。
- 修饰静态方法:锁住类对象。
- 修饰代码块:锁住指定对象,灵活性更高。
注意事项:
- 理解对象锁与类锁的区别。
- 注意锁的使用顺序,避免死锁。
- 选择合适的锁粒度,保证线程安全的同时优化性能。