JAVA实现生产者-消费者,使用信号量Semaphore

JAVA实现生产者-消费者,使用信号量Semaphore

简单看看什么是信号量:
Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。它其中的常用方法:
参数为许可证数量。
void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。(相当于加锁)
void release():释放一个许可,将其返回给信号量。(相当于释放锁)
int availablePermits():返回此信号量中当前可用的许可数。
boolean hasQueuedThreads():查询是否有线程正在等待获取。

先建个Buffer类用于做缓存区以及实现生产方法和校服方法

public class Buffer {
    //作为生产资料存在ArrayList缓存区里
    private int count;
    //定义一个 ArrayList 作为缓存区
    private ArrayList<Integer> pool = new ArrayList<>();
    private Semaphore mutex = new Semaphore(1); //定义只有一个许可证的信号量用做互斥信号量
    private Semaphore empty = new Semaphore(10); //定义有10个 许可证的信号量用做空缓存区
    private Semaphore full = new Semaphore(0);  //定义0个许可证的信号量,用于记录库存null还是not null

    //定义Wait方法 用于实现加锁功能
    public int Wait(Semaphore semaphore) {
        try {
            //从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。 实现了加锁的功能
            semaphore.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //返回此信号量中当前可用的许可数。
        return semaphore.availablePermits();
    }
    //定义Wait方法 用于实现解锁功能
    public int Notify(Semaphore semaphore){
        //释放一个许可,将其返回给信号量。(相当于释放锁)
        semaphore.release();
        return semaphore.availablePermits();
    }
    /**生产方法
     * @param area**/
    public void production(JTextArea area,int sleepTime) {
        while(true) {
            if (!algorithmGUI.sign) {
                break;
            }
            if (empty.availablePermits() == 0) {
                System.out.println("库存已满等待消费");
                area.append("  "+"库存已满等待消费"+"\n\n");
            }
            /**线程休眠0.5秒钟**/
            try {
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            /**
             *    通过  Wait(empty) 过得一个许可证 ,此时empty的许可证数量减一,直到许可证数量为0时线程阻塞,达到判断缓存区已满的效果
             *    Wait(mutex); 因为 mutex 只有一个许可证,当生产者获得 mutex的许可证时会让许可证数量为0 消费者就无法获取到 mutex的许可证
             *   导致消费者进入阻塞状态等待生产者归还许可证达到同步效果
             * */
            Wait(empty);
            Wait(mutex);
            pool.add(++count);
            area.append("  "+Thread.currentThread().getName()+"生产了第" + count + "个产品" + "\t库存容量:" + pool.size() + "\n\n");
            /**
             *     Notify(mutex); 归还mutex的许可证,当消费者获得许可证后进行消费
             *     Notify(full);  full的开始许可证数量为0,使用release()方法 让full的许可证加一,让消费者可以有许可证获取,达到判断库存是否为空还是非空
             * */
            Notify(mutex);
            /** 记录已经生产个数 **/
            Notify(full);
        }
    }
    //消费方法
    public void consumption(JTextArea area,int sleepTime) {
        while(true) {
            if (!algorithmGUI.sign) {
                break;
            }
                if (full.availablePermits() == 0) {
                    System.out.println("库存为空等待生产");
                    area.append("  "+Thread.currentThread().getName()+"进行消费结果失败----->"+"库存为空等待生产\n\n");
                }
                /**线程休眠0.5秒钟**/
                try {
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                /** 判断 full是否有许可证可以获取,如果有则说明库存不为空消费者可以进行消费,否则库存为空,等待生产者生产者 **/
                Wait(full);
                Wait(mutex);
                //获得产品
                int temp = pool.get(0);
                //消费产品将产品从list中移除
                pool.remove(0);
                area.append("  "+Thread.currentThread().getName() + "消费了第" + temp + "个产品" + "----->库存容量: " + pool.size() + "\n\n");
                /**
                 *   Notify(empty); 每当消费者消费一个产品,执行一次Notify(empty)方法,归还empty一个许可证让缓存区数量加一
                 *   Notify(mutex); 归还mutex的许可证让生产者可以进行生产
                 * **/
                Notify(empty);
                Notify(mutex);

        }
    }
}

建个consumer类实现Runnable让它开启线程调用生产方法,实现生产者的生产

//消费者线程
public class consumer implements Runnable{

    Buffer bf;
    JTextArea area;
    int sleepTime;
    public consumer(Buffer bf, JTextArea area,int sleepTime){
        this.bf = bf;
        this.area = area;
        this.sleepTime = sleepTime;
    }
    @Override
    public void run() {
        bf.consumption(area,sleepTime);
    }
}

建个producer类实现Runnable让它开启线程调用消费方法,实现消费者的消费

//生产者线程
public class producer implements Runnable{
    Buffer bf;
    JTextArea area;
    int sleepTime;
    public producer(Buffer bf, JTextArea area, int sleepTime){
        this.bf = bf;
        this.area = area;
        this.sleepTime = sleepTime;

    }

    @Override
    public void run() {
            bf.production(area,sleepTime);
    }
}

主方法----->创建多个线程开始进行测试


public class test {
    public static void main(String[] args) {
        buffer bf = new buffer();
        new Thread(new producer(bf)).start();
        new Thread(new consumer(bf),"1号消费者").start();
        new Thread(new consumer(bf),"2号消费者").start();
        new Thread(new consumer(bf),"3号消费者").start();
    }
}

执行的结果
在这里插入图片描述
修改生产方法和消费方法里面线程休眠的时间,让生产方法生产速度大于消费速度或者消费速度大于生产速度就可以出现临界区

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java实现生产者消费者问题的示例代码: ```java import java.util.LinkedList; import java.util.Queue; import java.util.Random; import java.util.concurrent.Semaphore; public class ProducerConsumerExample { private static final int BUFFER_SIZE = 10; private static final Semaphore mutex = new Semaphore(1); private static final Semaphore empty = new Semaphore(BUFFER_SIZE); private static final Semaphore full = new Semaphore(0); private static final Queue<Integer> buffer = new LinkedList<>(); public static void main(String[] args) { Thread producer = new Thread(new Producer()); Thread consumer = new Thread(new Consumer()); producer.start(); consumer.start(); } static class Producer implements Runnable { private final Random random = new Random(); @Override public void run() { while (true) { try { int item = random.nextInt(); empty.acquire(); mutex.acquire(); buffer.add(item); System.out.println("Produced item: " + item); mutex.release(); full.release(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class Consumer implements Runnable { @Override public void run() { while (true) { try { full.acquire(); mutex.acquire(); int item = buffer.remove(); System.out.println("Consumed item: " + item); mutex.release(); empty.release(); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } ``` 上述代码中,我们使用信号量实现线程之间的同步和互斥。其中,`mutex`是一个二元信号量,用于实现互斥访问共享缓冲区;`empty`是一个计数信号量,表示缓冲区中空闲的位置数;`full`也是一个计数信号量,表示缓冲区中已经存储的数据项数。 在生产者线程中,我们首先使用`empty.acquire()`获取一个空闲位置,然后使用`mutex.acquire()`获取互斥锁,向缓冲区中添加一个数据项,最后使用`mutex.release()`释放互斥锁,使用`full.release()`增加已存储的数据项数。 在消费者线程中,我们首先使用`full.acquire()`获取一个已存储的数据项,然后使用`mutex.acquire()`获取互斥锁,从缓冲区中移除一个数据项,最后使用`mutex.release()`释放互斥锁,使用`empty.release()`增加空闲位置数。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值