synchronized、ReentrantLock、Semaphore、CountDownLatch 的案例代码
以下是使用 Java 中的 synchronized、ReentrantLock、Semaphore、CountDownLatch 的案例代码:
使用 synchronized 实现线程互斥
public class SynchronizedExample {
private static int count = 0;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
synchronized (SynchronizedExample.class) {
for (int i = 0; i < 1000; i++) {
count++;
}
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
synchronized (SynchronizedExample.class) {
for (int i = 0; i < 1000; i++) {
count++;
}
}
}
});
t1.start();
t2.start();
}
}
上述代码中,我们使用 synchronized 关键字修饰 count 变量所在的类,实现了线程互斥。t1 和 t2 两个线程同时访问 count 变量时,只有一个线程能够成功,另一个线程会被阻塞。
使用 ReentrantLock 实现线程互斥
public class ReentrantLockExample {
private static int count = 0;
private ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
lock.lock();
try {
for (int i = 0; i < 1000; i++) {
count++;
}
} finally {
lock.unlock();
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
lock.lock();
try {
for (int i = 0; i < 1000; i++) {
count++;
}
} finally {
lock.unlock();
}
}
});
t1.start();
t2.start();
}
}
上述代码中,我们使用 ReentrantLock 实现了线程互斥。t1 和 t2 两个线程同时访问 count 变量时,只有一个线程能够成功,另一个线程会被阻塞。与 synchronized 关键字不同,ReentrantLock 允许多个线程同时获取锁,但同一个线程不能多次获取锁。
使用 Semaphore 实现线程互斥
public class SemaphoreExample {
private Semaphore semaphore = new Semaphore(1, 1);
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
semaphore.acquire();
try {
for (int i = 0; i < 1000; i++) {
// Do something
}
} finally {
semaphore.release();
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
semaphore.acquire();
try {
for (int i = 0; i < 1000; i++) {
// Do something
}
} finally {
semaphore.release();
}
}
});
t1.start();
t2.start();
}
}
上述代码中,我们使用 Semaphore 实现了线程互斥。t1 和 t2 两个线程同时访问 semaphore 信号量时,只有一个线程能够成功,另一个线程会被阻塞。Semaphore 信号量允许多个线程同时获取,但获取到的线程数不超过信号量的计数器值。
CountDownLatch 是 Java 并发编程中的一个同步工具,它可以用于实现线程间的同步。CountDownLatch 通过一个计数器来控制线程的同步,当计数器的值为 0 时,线程会被阻塞直到其他线程释放锁。
下面是一个使用 CountDownLatch 实现线程同步的示例代码:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
public class CountDownLatchExample {
private static final Object LOCK = new Object();
private static CountDownLatch countDownLatch;
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
countDownLatch = new CountDownLatch(1);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("Thread 1 started");
countDownLatch.countDown();
System.out.println("Thread 1 finished");
} finally {
lock.unlock();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
while (countDownLatch.getCount() > 0) {
System.out.println("Thread 2 waiting");
countDownLatch.wait();
}
System.out.println("Thread 2 started");
countDownLatch.countDown();
System.out.println("Thread 2 finished");
} finally {
lock.unlock();
}
}
});
t1.start();
t2.start();
}
}
在这个示例中,我们使用了一个 ReentrantLock 和一个 CountDownLatch 来实现线程同步。ReentrantLock 用于保护共享资源,而 CountDownLatch 用于控制线程的同步。
当 t1 线程开始执行时,它会先获取锁,然后调用 countDownLatch.countDown() 方法将计数器的值减 1。接着,t2 线程会等待计数器的值变为 0,然后开始执行。在 t2 线程执行过程中,它会先将计数器的值减 1,然后唤醒 t1 线程。
通过使用 CountDownLatch,我们可以实现线程间的同步,确保共享资源被正确地访问和修改。
