在Java编程中,线程是一种常用的并发编程模型,它可以让程序同时执行多个任务。然而,当多个线程同时访问共享资源时,可能会导致数据不一致或者其他竞争条件的问题。为了解决这些问题,Java提供了线程同步和锁机制。本文将详细介绍Java中的线程同步与锁机制。
1. 线程同步的概念
线程同步是指多个线程在执行过程中依次访问共享资源的一种机制。它可以保证共享资源在同一时间只能被一个线程访问,从而避免了数据不一致或者其他竞争条件的问题。
2. synchronized关键字
Java中可以使用synchronized
关键字来实现线程同步。synchronized
关键字可以修饰方法或者代码块。当一个方法或者代码块被synchronized
修饰时,该方法或者代码块在同一时间只能被一个线程执行。
具体而言,当一个线程进入被synchronized
修饰的方法或者代码块时,它会尝试获取该方法或者代码块的锁。如果锁被其他线程占用,那么该线程会被阻塞,直到锁被释放。一旦线程获取了锁,它就可以执行方法或者代码块中的逻辑,然后释放锁,让其他线程继续执行。
以下是synchronized
关键字的示例代码:
public class SyncExample {
private int count = 0;
public synchronized void increment() {
count++;
}
public static void main(String[] args) throws InterruptedException {
SyncExample syncExample = new SyncExample();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
syncExample.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
syncExample.increment();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(syncExample.count);
}
}
在上面的示例中,increment
方法被修饰为synchronized
,所以只能有一个线程可以同时执行该方法。通过创建两个线程分别调用increment
方法,可以保证共享变量count
的线程安全性。
3. Lock接口与ReentrantLock类
除了synchronized
关键字外,Java还提供了Lock
接口和ReentrantLock
类来实现线程同步。相比于synchronized
关键字,Lock
接口和ReentrantLock
类提供了更加灵活和强大的线程同步机制。
Lock
接口定义了一组与监视器锁(monitor lock)类似的方法,如lock()
、unlock()
、tryLock()
等。其中,lock()
方法用于获取锁,unlock()
方法用于释放锁,而tryLock()
方法尝试获取锁,如果获取成功返回true
,否则返回false
。
ReentrantLock
类是Lock
接口的一个实现,它提供了可重入的互斥锁。可重入锁意味着同一个线程可以多次获取锁,而不会引发死锁或其他异常情况。
以下是Lock
接口和ReentrantLock
类的示例代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
LockExample lockExample = new LockExample();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
lockExample.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
lockExample.increment();
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(lockExample.count);
}
}
在上面的示例中,increment
方法使用了ReentrantLock
来实现线程同步。通过调用lock()
方法获取锁,在try
块中执行方法逻辑,最后在finally
块中释放锁。这样可以保证共享变量count
的线程安全性。
4. 总结
本文详细介绍了Java中的线程同步与锁机制。通过使用synchronized
关键字、Lock
接口和ReentrantLock
类,我们可以实现线程安全的多线程编程。当多个线程访问共享资源时,使用线程同步和锁机制可以避免数据不一致或者其他竞争条件的问题。
本文来自极简博客,作者:星辰守望者,转载请注明原文链接:Java中的线程同步与锁机制详解