一,synchronized的特性
-
互斥性(Mutual Exclusion):
synchronized
可以保证同一时间只有一个线程可以执行被synchronized
修饰的方法或代码块。其他线程必须等待当前线程执行完成后才能访问。 -
可见性(Visibility):
synchronized
会确保在进入同步块之前,线程会从主存中刷新共享变量的值,而在退出同步块时,会将修改后的值刷新到主存中。这样可以保证多个线程看到的是同一份最新的数据。 -
有序性(Ordering):
synchronized
不仅保证了互斥性和可见性,还具有有序性的特性。也就是说,在多个线程并发执行的情况下,通过synchronized
保护的代码块的执行结果是按照一定的顺序来排列的,而不会出现乱序的情况。 -
原子性(Atomicity):
synchronized
保证了被它修饰的方法或代码块作为一个整体的执行是原子的,不会被其他线程中断。即使synchronized
修饰的方法或代码块中包含多个操作,它们也会被当作一个不可分割的单元来执行。
二,synchronized的使用
修饰方法:在方法声明时加上 synchronized
关键字,这意味着整个方法都是同步的。例如:
public synchronized void method() {
// 同步代码块
}
修饰代码块:使用 synchronized
关键字来修饰一段代码块,这样只有当线程获得了该代码块的锁时才能执行这段同步代码块。例如:
public void method() {
synchronized (this) {
// 同步代码块
}
}
修饰类:使用 synchronized
关键字来修饰整个类,这意味着该类的所有静态方法都是同步的,也就是说只有一个线程能够访问该类的静态方法。例如:
public class MyClass {
public static synchronized void method1() {
// 静态同步方法
}
public static synchronized void method2() {
// 静态同步方法
}
}
三,synchronized的锁机制
`synchronized` 关键字使用的是内置锁(Intrinsic Lock)或者称为监视器锁(Monitor Lock),它是Java中的一种基本锁机制。
当线程进入一个被 `synchronized` 修饰的方法或代码块时,它会尝试获取该方法或代码块所对应的对象的内置锁。如果该锁没有被其他线程占用,那么该线程就会成功获取到锁,并执行同步代码块;如果该锁已经被其他线程占用,那么该线程就会进入阻塞状态,直到获取到锁才能继续执行。
内置锁具有以下特性:
1. 独占性:内置锁是一种独占锁,每次只能有一个线程获得锁,其他线程必须等待。
2. 可重入性:同一个线程可以多次获取同一个锁而不会发生死锁。线程每次获取锁时,会将锁的持有计数加一,释放锁时,会将计数减一,只有计数为零时才真正释放锁。
3. 公平性:内置锁是非公平的,也就是说,当多个线程都在等待获取锁时,不保证按照先来先得的顺序分配锁。
4. 阻塞等待:如果一个线程尝试获取锁时发现锁已经被其他线程占用,那么它会进入阻塞状态,直到锁被释放。
5. 通知等待:当一个线程获取到锁并执行完同步代码块后,会释放锁并通知其他等待的线程,从而使它们有机会获取到锁并执行。
需要注意的是,`synchronized` 关键字只能对同一个对象进行加锁,因为它是以对象为单位的。如果需要对多个对象进行加锁,可以考虑使用 `Lock` 接口的实现类,如 `ReentrantLock`。