下面是对于Java多线程Condition接口的原理介绍:
Condition接口是什么?
在Java中,我们可以使用synchronized
、wait()
、notify()
、notifyAll()
等来进行线程同步和通信。而条件对象(Condition)是在Java 5中新增的,它可以更加灵活地控制线程的等待和唤醒,提供了更高级、更安全、更灵活的线程同步方式。
Condition的基本使用
条件对象是与一个锁绑定的,要创建一个条件对象,我们需要先获取锁,然后使用ReentrantLock
类的方法newCondition()
来创建:
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
这样我们就创建了一个条件变量,下一步就可以通过调用condition
的await()
方法使得线程进入等待状态,直到调用condition
的signalAll()
方法或者signal()
方法唤醒线程。
下面是一个简单的示例,两个线程分别执行加和减操作,当结果为零时,主线程输出结果并结束程序。具体的实现过程如下:
public class ConditionDemo {
private int sum;
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void add() {
lock.lock();
try {
sum++;
System.out.println(Thread.currentThread().getName() + " add: " + sum);
condition.signalAll();
} finally {
lock.unlock();
}
}
public void sub() {
lock.lock();
try {
while (sum == 0) {
condition.await();
}
sum--;
System.out.println(Thread.currentThread().getName() + " sub: " + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ConditionDemo demo = new ConditionDemo();
Runnable addTask = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
demo.add();
}
}
};
Runnable subTask = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
demo.sub();
}
}
};
Thread addThread1 = new Thread(addTask);
Thread addThread2 = new Thread(addTask);
Thread subThread = new Thread(subTask);
addThread1.start();
addThread2.start();
subThread.start();
try {
addThread1.join(); // 等待线程结束
addThread2.join();
subThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Result: " + demo.sum);
}
}
上述程序中,使用了一个变量sum
来保存加减的结果。在加操作中,我们先获取锁,然后将sum
增加1,输出结果,并唤醒所有等待condition
的线程。在减操作中,我们先获取锁,然后不断判断sum
是否为0,如果为0,则调用condition
的await()
方法等待;直到被唤醒后,将sum
减1,并输出结果。在主线程中,我们启动两个加操作线程和一个减操作线程,等待所有线程运行结束后,输出结果。
使用Condition实现生产者-消费者模式
生产者-消费者模式是大家比较熟悉的一种应用场景。可以使用Condition来实现,示例如下:
public class ProducerConsumerDemo {
private LinkedList<Integer> buffer = new LinkedList<Integer>();
private ReentrantLock lock = new ReentrantLock();
private Condition notEmpty = lock.newCondition();
private Condition notFull = lock.newCondition();
public void produce() {
lock.lock();
try {
while (buffer.size() == 10) {
notFull.await();
}
int value = new Random().nextInt(100);
buffer.addLast(value);
System.out.println(Thread.currentThread().getName() + " produce " + value);
notEmpty.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public int consume() {
lock.lock();
try {
while (buffer.size() == 0) {
notEmpty.await();
}
int value = buffer.removeFirst();
System.out.println(Thread.currentThread().getName() + " consume " + value);
notFull.signalAll();
return value;
} catch (InterruptedException e) {
e.printStackTrace();
return -1;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ProducerConsumerDemo demo = new ProducerConsumerDemo();
Runnable produceTask = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
demo.produce();
}
}
};
Runnable consumeTask = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
demo.consume();
}
}
};
Thread producer1 = new Thread(produceTask, "producer1");
Thread producer2 = new Thread(produceTask, "producer2");
Thread consumer1 = new Thread(consumeTask, "consumer1");
Thread consumer2 = new Thread(consumeTask, "consumer2");
producer1.start();
producer2.start();
consumer1.start();
consumer2.start();
try {
producer1.join();
producer2.join();
consumer1.join();
consumer2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述示例中,我们使用了一个LinkedList
来存储数据。在生产操作中,如果buffer
已经满了,那就调用notFull.await()
等待;直到有消费者调用了consume()
方法,拿走了一些数据,此时有足够的空间存储新的数据,就可以唤醒正在等待的生产者线程。在消费操作中,如果buffer
为空,就调用notEmpty.await()
等待;直到有生产者调用了produce()
方法,放入了一些数据,此时就可以从buffer
中取出数据,唤醒正在等待的消费者线程。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程Condition接口原理介绍 - Python技术站