java lock condition example

本文介绍了一个使用Java实现的简单并发缓冲区设计,该设计通过ReentrantLock和Condition来协调生产者和消费者之间的线程同步问题。生产者从文件中读取数据并将其插入到缓冲区,而消费者则从缓冲区读取数据进行处理。

public class FileMock {
private String content[];
private int index;

public FileMock(int size, int length){
content = new String[size];
for(int i=0; i<size; i++){
StringBuilder buffer = new StringBuilder(length);
for(int j=0; j<length; j++){
int indice = (int)Math.random() * 255;
buffer.append((char)indice);
}
content[i] = buffer.toString();
}
index = 0;
}

public boolean hasMoreLines(){
return index < content.length;
}

public String getLine(){
if(this.hasMoreLines()){
System.out.println("Mock: " + (content.length-index));
return content[index++];
}

return null;
}
}



import java.util.LinkedList;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
/**
* Created by Administrator.
*/
public class Buffer {
private LinkedList<String> buffer;
private int maxSize;
private ReentrantLock lock;
private Condition lines;
private Condition space;
private boolean pendingLines;

public Buffer(int maxSize){
this.maxSize = maxSize;
buffer = new LinkedList<String>();
lock = new ReentrantLock();
lines = lock.newCondition();
space = lock.newCondition();

pendingLines = true;
}

public void insert(String line){
lock.lock();
try{
while(buffer.size() == maxSize){
space.await();
}

buffer.offer(line);
System.out.printf("%s: Inserted Line: %d\n", Thread.currentThread().getName(), buffer.size());
lines.signalAll();
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}

public String get(){
String line = null;
lock.lock();
try{
while((buffer.size() == 0) && (hasPendingLines())){
lines.await();
}

if(hasPendingLines()){
line = buffer.poll();
System.out.printf("%s: Line Readed: %d\n", Thread.currentThread().getName(), buffer.size());
space.signalAll();
}
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
return line;
}

public void setPendingLines(boolean pendingLines){
this.pendingLines = pendingLines;
}

public boolean hasPendingLines(){
return pendingLines || buffer.size() > 0;
}
}



public class Producer implements Runnable {
private FileMock mock;
private Buffer buffer;

public Producer(FileMock mock, Buffer buffer){
this.mock = mock;
this.buffer = buffer;
}

@Override
public void run(){
buffer.setPendingLines(true);
while(mock.hasMoreLines()){
String line = mock.getLine();
buffer.insert(line);
}
buffer.setPendingLines(false);
}
}



import java.util.Random;

/**
* Created by Administrator.
*/
public class Consumer implements Runnable {
private Buffer buffer;
public Consumer(Buffer buffer){
this.buffer = buffer;
}

@Override
public void run(){
while(buffer.hasPendingLines()){
String line = buffer.get();
processLine(line);
}
}

private void processLine(String line){
try{
Random random = new Random();
Thread.sleep(random.nextInt(100));
}catch(InterruptedException e){
e.printStackTrace();
}
}
}



public class Main {
public static void main(String[] args){
FileMock mock = new FileMock(100, 10);
Buffer buffer = new Buffer(20);

Producer producer = new Producer(mock, buffer);
Thread threadProducer = new Thread(producer, "Producer");

Consumer consumers[] = new Consumer[3];
Thread threadConsumers[] = new Thread[3];
for(int i=0; i<3; i++){
consumers[i] = new Consumer(buffer);
threadConsumers[i] = new Thread(consumers[i], "Consumer " + i);
}

threadProducer.start();
for(int i=0; i<3; i++){
threadConsumers[i].start();
}
}
}
### 使用Java中的Lock接口实现线程间通信 #### 创建锁对象并初始化条件变量 为了使用 `Lock` 接口来实现线程间的通信,通常会配合 `Condition` 对象一起工作。下面是一个简单的例子展示如何利用 `ReentrantLock` 及其关联的 `Condition` 来完成生产者-消费者模式下的线程通信。 ```java import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ProducerConsumerExample { private final Queue<Integer> queue = new LinkedList<>(); private static final int LIMIT = 10; // 队列容量上限 private final Lock lock = new ReentrantLock(); private final Condition notFull = lock.newCondition(); private final Condition notEmpty = lock.newCondition(); public void produce(int value) throws InterruptedException { lock.lock(); try { while (queue.size() == LIMIT) { System.out.println("队列已满"); notFull.await(); // 如果满了就等待 } queue.offer(value); System.out.println("生产 -> " + value); notEmpty.signal(); // 唤醒正在等待的消费线程 } finally { lock.unlock(); } } public Integer consume() throws InterruptedException { lock.lock(); try { while (queue.isEmpty()) { System.out.println("队列为空"); notEmpty.await(); // 如果空了就等待 } Integer value = queue.poll(); System.out.println("消费 <- " + value); notFull.signal(); // 唤醒正在等待的生产线程 return value; } finally { lock.unlock(); } } } ``` 在这个案例里,`produce()` 方法用来向共享资源(这里是 `Queue`)添加数据项;而 `consume()` 则是从其中移除数据项。两个方法都围绕着同一个 `ReentrantLock` 锁实例操作,并且分别定义了自己的 `Condition` 实例用于通知对方何时可以继续运行[^4]。 #### 生产者消费者的启动 为了让上述逻辑生效,还需要编写相应的生产者和消费者线程: ```java // 启动多个生产者和消费者线程... ProducerConsumerExample example = new ProducerConsumerExample(); for (int i = 0; i < 5; ++i) { Thread producerThread = new Thread(() -> { for (;;) { try { example.produce((int)(Math.random()*10)); Thread.sleep(100); // 模拟延迟 } catch (InterruptedException e) {} } }); Thread consumerThread = new Thread(() -> { for (;;) { try { example.consume(); Thread.sleep(100); // 模拟处理时间 } catch (InterruptedException e) {} } }); producerThread.start(); consumerThread.start(); } ``` 此部分代码展示了如何创建若干个生产和消费的工作线程,它们将不断循环地调用之前定义的方法来进行实际的数据交换过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值