阿里一面上来就让手写一个多线程模型,利用condition来实现1和0的交替执行,着实把我弄懵逼了,凭借着自己微弱的记忆,大致写出了如下:
基本思路是:
1、线程 操作 (方法) 资源类
2、判断 干活 通知
3、利用while判断来防止虚假唤醒机制
第一种方法利用Lock进行加锁解锁:
public class ProducerAndConsumer {
public static void main(String[] args) {
Food food = new Food();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
food.produce();
} catch (Exception e) {
e.printStackTrace();
}
}
},"生产者").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
food.consumer();
} catch (Exception e) {
e.printStackTrace();
}
}
},"消费者").start();
}
}
/**
* 线程操作的资源
*/
class Food{
private int number = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
/**
* 打印1
* @throws Exception
*/
public void produce() throws Exception{
lock.lock();
try {
// 1. number等于0,才开始生产,不等于0,则生产者处于等待状态
// 这里必须用while判断,否则可能产生虚假唤醒
while(number != 0){
condition.await();
}
// 2. 等于0,则开始干活
number++;
System.out.println("生产者生产.... " + number);
// 3. 生产者生产完了之后,需要通知唤醒消费者
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
/**
* 打印0
* @throws Exception
*/
public void consumer() throws Exception{
lock.lock();
try {
// 1. number ==0 ,生产者等待
while(number == 0){
condition.await();
}
// 2. 如果number != 0,则消费者消费
number--;
System.out.println("消费者消费.... " + number);
// 3. 消费者消费之后,通知唤醒生产者
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
方法二:利用Synchronized关键字进行加锁解锁:
public class Juc013WaitNotify {
static int number = 0;
static Object object = new Object();
public static void main(String[] args) throws Exception{
Thread one = new Thread(new PrintOne(),"PrintOne");
one.start();
TimeUnit.SECONDS.sleep(1);
Thread zero = new Thread(new printZero(),"PrintTwo");
zero.start();
}
/**
* 打印1
*/
static class PrintOne implements Runnable{
@Override
public void run(){
for(int i = 0;i < 100;i++){
// 进来操作之前,先加锁
synchronized (object){
while(number == 0){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("---------------打印1---------------");
number = 0;
object.notifyAll();
}
}
}
}
static class printZero implements Runnable{
@Override
public void run() {
for(int i = 0;i < 100;i++){
synchronized (object){
while (number == 1){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("---------------打印0---------------");
number = 1;
object.notifyAll();
}
}
}
}
}
基本的处理逻辑:
等待方遵循的原则:
- 获取对象的锁
- 如果条件不满足,则调用对象的wait()方法,被通知后仍然要检查条件
- 条件满足才执行相应的业务
大致的代码为:
synchronized(对象){
while(条件不满足){
对象.wait()
}
// 条件满足,则执行相应的逻辑
……………………
}
通知方的工作:
- 获取对象的锁
- 改变对象
- 通知等待在对象上的线程
synchronized(对象){
改变条件
对象.notifyAll()
}