之前写了synchronized实现生产者消费者问题,这次用的是lock实现。还有一个就是condition,什么是condition呢?
官方文档是这么说的
简单点,就是替代对象监视器了。它的两个常用方法分别是await()
和signal()
,相当于之前的wait()
和notify()
。我们具体来看代码实现
package JUC;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockPC {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
resource.incresement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
resource.decrease();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
resource.incresement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
resource.decrease();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
//资源类
static class Resource {
//定义一个可重入锁
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//生产资源,生产者对其加1,消费者对其减1
private int num = 0;
public void incresement() throws InterruptedException {
lock.lock();
try {
//对增加进行判断
while (num > 0) {
condition.await();
}
num++;
System.out.println(Thread.currentThread().getName() + "->" + num);
//通知其他线程对其操作
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrease() throws InterruptedException {
lock.lock();
try {
//对减少进行判断
while (num == 0) {
condition.await();
}
num--;
System.out.println(Thread.currentThread().getName() + "->" + num);
//通知其他线程对其操作
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
打印输出,和我们用synchronized实现一样,有规律的生产和消费。
A->1
B->0
A->1
B->0
A->1
B->0
C->1
B->0
A->1
B->0
C->1
B->0
A->1
B->0
C->1
B->0
A->1
B->0
C->1
B->0
A->1
D->0
C->1
D->0
A->1
......
可是我们发现虽然他们是有规律的生产和消费,但是并没有按照我们的线程的顺序来打印。唤醒的时候消费和生产都在竞争。那么我们如何让线程按照我们指定的顺序来达到精准唤醒呢?
我们可以多定义几个condition,然后在执行完唤醒指定的condition!
package JUC;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockPC {
public static void main(String[] args) {
Resource resource = new Resource();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
resource.incresementA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
resource.decreaseB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
resource.incresementC();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
resource.decreaseD();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
//资源类
static class Resource {
//定义一个可重入锁
Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
Condition conditionD = lock.newCondition();
//生产资源,生产者对其加1,消费者对其减1
private int num = 0;
public void incresementA() throws InterruptedException {
lock.lock();
try {
//对增加进行判断
while (num > 0) {
conditionA.await();
}
num++;
System.out.println(Thread.currentThread().getName() + "->" + num);
//通知其他线程对其操作
conditionB.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decreaseB() throws InterruptedException {
lock.lock();
try {
//对减少进行判断
while (num == 0) {
conditionB.await();
}
num--;
System.out.println(Thread.currentThread().getName() + "->" + num);
//通知其他线程对其操作
conditionC.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
};
}
public void incresementC() throws InterruptedException {
lock.lock();
try {
//对增加进行判断
while (num > 0) {
conditionC.await();
}
num++;
System.out.println(Thread.currentThread().getName() + "->" + num);
//通知其他线程对其操作
conditionD.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decreaseD() throws InterruptedException {
lock.lock();
try {
//对减少进行判断
while (num == 0) {
conditionD.await();
}
num--;
System.out.println(Thread.currentThread().getName() + "->" + num);
//通知其他线程对其操作
conditionA.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
};
}
}
}
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
A->1
B->0
C->1
D->0
Condition实现可以提供Object监视器方法的行为和语义,例如有保证的通知顺序,或者在执行通知时不需要锁定。 如果一个实现提供了这样的专门的语义,那么实现必须记录这些语义。
需要注意的是,condition也是会发生虚假唤醒的,所以我们需要把判断写进循环语句里。
网友评论