下面将详细讲解Java多线程并发中的ReentrantLock。
什么是ReentrantLock
ReentrantLock是Java多线程并发中的一个锁机制,它具有以下特点:
- 可重入锁(Reentrant),也就是同一线程可以多次获取锁而不会出现死锁。
- 可以具有公平性(Fairness),也就是等待时间最长的线程会先获取锁。
- 支持中断(Interruptible)的锁,可以在等待锁的过程中支持线程的中断。
- 支持条件(Condition)的等待和唤醒,可以在不同的条件下等待和唤醒线程。
ReentrantLock的使用方式
以下是ReentrantLock的基本使用方式:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
final Lock lock = new ReentrantLock();
public void task() {
lock.lock(); // 获取锁
try {
// do something 线程安全的操作
} finally {
lock.unlock(); // 释放锁
}
}
}
在上面的代码中,我们通过创建一个Lock接口类型的变量,来实例化一个ReentrantLock对象,随后在需要的时候通过lock()方法获取锁,通过unlock()方法释放锁。
ReentrantLock的示例说明
接下来,我们将通过两个示例说明ReentrantLock的应用。
示例一:交替打印
在这个示例中,我们会创建两个线程A和B,它们将交替打印1-100的数字。因为涉及到多个线程共享同一个资源,所以需要同步处理。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PrintNumberThread implements Runnable {
private volatile int value = 1;
private final int maxValue;
private final Lock lock;
private final String threadName;
public PrintNumberThread(Lock lock, String threadName, int maxValue) {
this.lock = lock;
this.threadName = threadName;
this.maxValue = maxValue;
}
@Override
public void run() {
while (value <= maxValue) {
lock.lock();
try {
if ((value % 2 == 0 && "偶数线程".equals(threadName)) || (value % 2 != 0 && "奇数线程".equals(threadName))) {
System.out.println(threadName + ": " + value++);
}
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
Lock lock = new ReentrantLock();
PrintNumberThread oddThread = new PrintNumberThread(lock, "奇数线程", 100);
PrintNumberThread evenThread = new PrintNumberThread(lock, "偶数线程", 100);
new Thread(oddThread).start();
new Thread(evenThread).start();
}
}
在上面的代码中,我们定义了一个PrintNumberThread类,它实现了Runnable接口,并传递了一个ReentrantLock对象和线程名称。在run()方法中,我们首先获取锁再尝试输出数字,如果是偶数线程就输出偶数,奇数线程就输出奇数,最后释放锁。
在主函数中,我们创建了两个线程,并启动它们,它们将会交替打印1-100的数字。
示例二:生产者和消费者
在这个示例中,我们创建了一个生产者和一个消费者线程,并使用一个阻塞队列来进行同步处理。生产者将会不断地生产并放置数据到阻塞队列,而消费者则会从队列中取出数据并进行处理。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ProducerConsumer {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
Thread producer = new Thread(() -> {
while (true) {
lock.lock();
try {
if (queue.size() < 10) {
String value = String.valueOf(System.currentTimeMillis());
System.out.println(Thread.currentThread().getName() + "生产了" + value);
queue.put(value);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
Thread consumer = new Thread(() -> {
while (true) {
lock.lock();
try {
if (queue.size() > 0) {
String value = queue.take();
System.out.println(Thread.currentThread().getName() + "消费了" + value);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
producer.start();
consumer.start();
}
}
在上面的代码中,我们首先定义了一个ReentrantLock对象和一个BlockingQueue对象。在生产者线程中,如果队列还没有达到最大长度,就生产并放置一个数据到队列中。在消费者线程中,如果队列中还有数据就从队列中取出并进行消费。注:为了简化示例,这里并未考虑线程等待唤醒和中断等复杂情况。
总结
在Java多线程并发中,ReentrantLock提供了灵活的锁机制,支持可重入性、公平性、中断、条件等操作。通过ReentrantLock可以保证线程安全性,有效地避免数据竞争等问题。
以上就是关于Java多线程并发ReentrantLock的完整攻略和示例说明。希望对读者有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java 多线程并发ReentrantLock - Python技术站