多线程08--管程

管程 (英语:Monitors,也称为监视器) :是一种程序结构,结构内的多个子程序(对象模块)形成的多个工作线程互斥访问共享资源。这些共享资源一般是硬件或一群变量。管程实现了在一个时间点,最多只有一个线程在执行管程的某个子程序。与那些通过修改数据结构实现互斥访问的并发程序设计相比,管程实现很大程度上简化了程序设计。管程提供了一种机制,线程可以临时放弃互斥访问,等待某些条件得到满足后,重新获得执行权恢复它的互斥访问。

组成元素::

运行机制

当一个线程执行管程中的一个子程序(例如:出队列、入队列)时,称为占用(occupy)该管程, 管程的实现确保了在一个时间点,最多只有一个线程占用了该管程,这是管程的互斥锁访问性质。当线程要调用一个定义在管程中的子程序时,必须等到已经没有其它线程在执行管程中的某个子程序。在管程的简单实现中,编译器为每个管程对象自动加入一把私有的互斥锁。该互斥锁初始状态为解锁,在管程的每个公共子程序的入口给该互斥锁加锁,在管程的每个公共子程序的出口给该互斥锁解锁。

----------------------以上来自维基百科-----------------------

上述运行机制简单可以归纳如下(便于理解):

  • 生产者在缓存队列满时不再生产,进入等待队列
  • 消费者在缓存队列为空时不再消费,进入等待队列
  • 当生产者生产可消费的资源时通知处于等待队列消费者,进行消费
  • 当消费者没有资源时通知等待生产者生产

 

下面利用管程来实现多线程中比较经典的生产者消费者模型。

  • 管程主实现类:
package pubsub;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName : MQueue
 * @Description:
 * @Author: liulianglin
 * @Date: 2021/4/2 12:04
 * @Version : 1.0
 */
public class MQueue<T> {
    /**
     * 共享变量
     */
    private final Lock lock = new ReentrantLock();

    /**
     * 条件变量: 当生产者生产数据遇到队列满时,生产者进入该等待队列,等待消费者消费共享数据后唤醒它。
     */
    private final Condition queueFullWait = lock.newCondition();

    /**
     * 条件变量: 当消费者消费数据遇到队列为空时,消费者进入等待队列,等待生产者生产数据后唤醒它
     */
    private final Condition queueEmptyWait = lock.newCondition();

    /**
     * 共享数据的队列
     */
    private final List<T> objectList = new ArrayList<>();

    /**
     * 队列容量
     */
    private int listCapacity;

    /**
     * 队列中当前存储数据的数量
     */
    private int curListSize;

    MQueue(int listCapacity){
        this.listCapacity = listCapacity;
    }

    /**
     * 生产数据:入队列
     */
    public void produce(T obj){
        //获取锁
        lock.lock();
        try {
            if (curListSize >= listCapacity){
                //如果当前队列大小已经到达最大容量,则生产者线程进入等待队列中
                System.out.println("队列满了,生产者进入等待队列...");
                queueFullWait.await(1, TimeUnit.MILLISECONDS);
            }
            objectList.add(obj);
            curListSize++;
            //通知处于queueEmptyWait等待状态的线程
            System.out.println("生产完一条数据,通知处于queueEmptyWait等待状态的线程...");
            queueEmptyWait.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //释放锁
            lock.unlock();
        }
    }

    /**
     * 消费数据:出队列
     */
    public T consume(){
        T result = null;
        lock.lock();
        try{
            if (curListSize <= 0){
                //如果当前队列为空,则进入等待队列中
                System.out.println("当前队列为空,消费者进入等待队列...");
                queueEmptyWait.await(1, TimeUnit.MILLISECONDS);
            }
            //移除第一个
            result = objectList.remove(0);
            curListSize--;
            //通知处于queueFullWait等待队列中的生产者
            System.out.println("消费者消费完一条数据,通知处于queueFullWait等待队列中的生产者...");
            queueFullWait.signal();
        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            lock.unlock();
        }
        return result;
    }
}
  • 生产者线程:
package pubsub;

/**
 * @ClassName : ProducerThread
 * @Description:
 * @Author: liulianglin
 * @Date: 2021/4/2 12:33
 * @Version : 1.0
 */
public class ProducerThread implements Runnable {
    private final MQueue mQueue;

    /**
     * 需要生产的数据总量
     */
    private final int needProduceCount;

    ProducerThread(MQueue mQueue, int needProduceCount){
        this.mQueue = mQueue;
        this.needProduceCount = needProduceCount;
    }

    @Override
    public void run() {
        //生产数据
        for (int i = 0; i <= needProduceCount; i++) {
            //构造数据
            Object object = new Object();
            mQueue.produce(object);
            System.out.println(i+ "-- 生产: "+object );
        }
    }
}
  • 消费者线程:
package pubsub;

/**
 * @ClassName : ConsumerThread
 * @Description:
 * @Author: liulianglin
 * @Date: 2021/4/2 12:37
 * @Version : 1.0
 */
public class ConsumerThread implements Runnable{
    private final MQueue mQueue;

    private final int needConsumeSize;

    ConsumerThread(MQueue mQueue, int needConsumeSize){
        this.mQueue = mQueue;
        this.needConsumeSize = needConsumeSize;
    }

    @Override
    public void run() {
        for (int i = 0; i <= needConsumeSize; i++) {
            Object result = mQueue.consume();
            System.out.println(i+ "-- 消费:"+result);
        }
    }
}
  • 主测试类:
package pubsub;

/**
 * @ClassName : MainTest
 * @Description:
 * @Author: liulianglin
 * @Date: 2021/4/2 12:53
 * @Version : 1.0
 */
public class MainTest {
    public static void main(String[] args) {
        MQueue mQueue = new MQueue(1);
        new Thread(new ProducerThread(mQueue, 2)).start();
        new Thread(new ConsumerThread(mQueue, 2)).start();

    }
}
  • 运行结果:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值