【操作系统】实验——线程的同步与互斥(Java)

实验内容

 编写java程序,使用Thread 类或Runnable接口创建线程,实现生产者消费者问题。
要求:
1)分析指出问题中的临界资源,并在代码中标注出临界区;
2)能够采用synchronized、wait()和notify()(或notifyall())等方法实现线程的互斥与同步;
3)各线程在生产或者消费时需要有输出标识,格式为“生产/消费线程 + i + 生产/消费了一个商品,目前商品总数为n”,各线程完成生产或消费后,sleep()函数使线程进入阻塞,通过改变sleep()函数的参数,改变生产与消费的执行顺序以及频率,并讲结果截图附简要说明原因。

基础知识简介

 在java中,wait()、notify()方法的关系如同开关一样,一个方法让线程进入阻塞状态,一个方法唤醒等待中的线程,让其进行运作。这样的的等待-唤醒的方式,也保护了临界资源,防止并发产生问题。但和sleep()不一样的是,使用wait()以及notify()时,必须先获得锁!只能在synchronized锁范围中进行使用!

  • wait():使调用该方法的线程释放共享资源锁(sleep方法调用后不会释放锁),然后从运行状态退出,进入等待队列,直到被再次唤醒。
  • notify():随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程。
  • notifyAll():使所有正在等待队列中等待同一共享资源的全部线程退出等待队列,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,这取决于JVM虚拟机的实现。

希望对该知识有更深入了解的可以参考这篇文章:彻底搞懂Java的等待-通知(wait-notify)机制

实验过程

 问题中的临界资源为生产者生产的资源,临界区为存放资源的区域。
 在过程中,使用synchronized对线程加锁,保护临界资源在其他线程访问的时候不会被读取,当临界区中已经无法存放临界资源的时候,使用wait()方法,释放锁,直到消费者线程消费资源后唤醒生产者线程。在完成对资源的生产后,使用notify() 方法,不会立即释放锁,当执行完同步代码块就会释放对象的锁。释放后便于消费者线程对资源进行操作。消费者线程中的处理同步互斥问题的操作也同理。各线程完成生产或消费后,sleep()函数使线程进入阻塞,通过改变sleep()函数的参数,能够改变生产与消费的执行顺序以及频率。当生产者线程sleep(1000)时,生产者线程会在生产资源后阻塞1秒钟,然后继续执行,同时当消费者线程sleep(5000)时,消费者线程会在消费资源后阻塞5秒钟,然后继续执行。

代码

public class ProducerConsumer{
    private static final int BUFFER_SIZE = 10;//临界区
    private static int bufferCount = 0;//临界资源
    private static final Object bufferLock = new Object();

    public static class Producer implements Runnable{
        @Override
        public void run() {
            while (true) {
                synchronized (bufferLock) {//对对象进行加锁
                    while (bufferCount == BUFFER_SIZE) {//临界区满
                        try {
                            bufferLock.wait();//释放锁,进入等待状态
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    bufferCount ++;
                    System.out.println("生产线程" + Thread.currentThread().getId() + "生产了一个商品,目前商品总数为" + bufferCount);
                    bufferLock.notifyAll();//完成代码后,释放锁,让下一线程对资源操作
                }
                try {
                    Thread.sleep(1000);//设置线程阻塞时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static class Consumer implements Runnable{
        @Override
        public void run() {
            while (true) {
                synchronized (bufferLock) {
                    while (bufferCount == 0) {//临界区无资源消费
                        try {
                            bufferLock.wait();//释放锁,进入等待状态
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    bufferCount--;
                    System.out.println("消费线程" + Thread.currentThread().getId() + "消费了一个商品,目前商品总数为" + bufferCount);
                    bufferLock.notifyAll();
                }
                try {
                    Thread.sleep(5000);//设置线程阻塞时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());
        producer.start();
        consumer.start();
    }
}
  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值