内置锁(也称为监视器锁或互斥锁)是Java语言提供的一种基本的线程同步机制。在Java中,每个对象都自动持有一个内置的锁,这个锁也被称为对象的监视器锁(monitor lock)。当你使用synchronized
关键字来同步一个代码块或方法时,你就是在使用这个内置锁。
内置锁的特点:
-
非公平性:Java的内置锁是非公平的,这意味着等待的线程不会按照它们请求锁的顺序来获得锁。哪个线程将获得锁是由JVM的线程调度器决定的。
-
不可重入:内置锁是不可重入的,意味着如果一个线程已经持有了某个对象的内置锁,它不能再次获取同一个对象的锁,否则会导致死锁。这与可重入锁(如
ReentrantLock
)形成对比,后者允许一个线程多次获取同一个锁。 -
自动释放:当一个线程执行完同步代码块或方法后,内置锁会自动释放,这样其他等待该锁的线程就可以获取它。
-
可中断性:与
ReentrantLock
不同,内置锁不支持中断。当一个线程等待获取锁时,它不能被其他线程中断。
使用场景:
-
简单的同步需求:对于简单的同步需求,如访问共享资源的单个方法或代码块,内置锁通常足够使用。
-
不需要细粒度控制:当你不需要对锁进行细粒度控制(如公平锁、非公平锁、尝试获取锁等)时,可以使用内置锁。
-
性能要求不高:内置锁通常比高级锁(如
ReentrantLock
)具有更低的性能开销,因为它是由JVM隐式管理的。
示例代码:
下面是一个使用内置锁的简单示例:
public class SynchronizedExample { private int count = 0; // 使用内置锁同步方法 public synchronized void increment() { count++; } // 使用内置锁同步代码块 public void incrementBlock() { synchronized (this) { count++; } } public static void main(String[] args) { SynchronizedExample example = new SynchronizedExample(); // 启动两个线程来增加count Thread t1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { example.increment(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { example.incrementBlock(); } }); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Final count: " + example.count); }
}
在这个示例中,increment方法和incrementBlock代码块都是使用synchronized关键字来同步的,这意味着它们都会获取对象的内置锁。因此,当一个线程执行这些同步代码时,其他线程必须等待,直到锁被释放。