解释synchronized关键字的作用。
`synchronized`关键字在Java中用于实现线程同步,确保在多线程环境下,某个代码块或方法在同一时间只能被一个线程执行,从而防止多个线程同时访问共享资源时引发的数据不一致问题。
### synchronized的作用和用法
`synchronized`关键字可以用于方法或代码块,分别称为同步方法和同步块。以下是它们的用法和作用:
#### 1. 同步方法(Synchronized Method)
同步方法可以是实例方法或静态方法,用于确保同一时间只有一个线程可以执行该方法。
##### 实例方法
实例方法同步确保同一个对象的同步方法在同一时间只能被一个线程访问。
```java
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
```
##### 静态方法
静态方法同步确保同一时间只有一个线程可以访问该类的静态同步方法。
```java
public class Counter {
private static int count = 0;
public static synchronized void increment() {
count++;
}
public static synchronized int getCount() {
return count;
}
}
```
#### 2. 同步块(Synchronized Block)
同步块用于同步方法中的部分代码。它比同步方法更加灵活,可以减少同步的范围,从而提高性能。同步块可以指定对象作为锁(锁对象)。
```java
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
public int getCount() {
synchronized (lock) {
return count;
}
}
}
```
### synchronized的实现原理
`synchronized`关键字依赖于Java对象头中的监视器锁(Monitor Lock)来实现。每个对象都可以作为一个锁,当一个线程进入同步方法或同步块时,它会自动获取该对象的锁,其他试图进入相同锁的线程会被阻塞,直到持有锁的线程释放锁为止。
#### 锁的类型
- **对象锁(Instance Lock)**:用于实例方法和同步块,锁对象是当前实例对象(`this`)。
- **类锁(Class Lock)**:用于静态方法和同步块,锁对象是当前类的Class对象(`ClassName.class`)。
### 示例代码
以下是一个使用`synchronized`关键字的示例,展示如何确保线程安全地操作共享资源:
```java
public class SynchronizedExample {
private int count = 0;
// 同步实例方法
public synchronized void increment() {
count++;
}
// 同步块
public void incrementWithBlock() {
synchronized (this) {
count++;
}
}
public int getCount() {
return count;
}
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
// 创建多个线程同时访问共享资源
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
// 等待两个线程执行完毕
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 打印最终的计数结果
System.out.println("Final count: " + example.getCount()); // 预期输出:2000
}
}
```
### 总结
- **synchronized关键字**用于实现线程同步,防止多个线程同时访问共享资源时引发的数据不一致问题。
- **同步方法**和**同步块**是两种常见的使用方式,分别用于同步整个方法或代码块中的特定部分。
- **锁对象**(对象锁和类锁)用于控制线程对共享资源的访问。
- 使用`synchronized`关键字可以确保线程安全,但需要注意锁的粒度,以避免性能问题。