Java模拟生产者消费者问题

Java模拟生产者消费者问题

一、Syncronized方法详解

解决生产者消费这问题前,先来了解一下Java中的syncronized关键字。

synchronized关键字用于保护共享数据。请大家注意"共享数据",你一定要分清哪些数据是共享数据,如下面程序中synchronized关键字保护的不是共享数据(其实在这个程序中synchronized关键字没有起到任何作用,此程序的运行结果是不可预先确定的)。这个程序中的t1,t2是 两个对象(pp1,pp2)的线程。JAVA是面向对象的程序设计语言,不同的对象的数据是不同的,pp1,pp2有各自的run()方法,而 synchronized使同一个对象的多个线程,在某个时刻只有其中的一个线程可以访问这个对象的synchronized数据。每个对象都有一个"锁标志",当这个对象的一个线程访问这个对象的某个synchronized数据时,这个对象的所有被synchronized修饰的数据将被上锁(因为" 锁标志"被当前线程拿走了),只有当前线程访问完它要访问的synchronized数据时,当前线程才会释放"锁标志",这样同一个对象的其它线程才有机会访问synchronized数据。

package SyncronizedMenthodTest;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.PrintStream;

 

public classPrintProgram implements Runnable {

 

    public synchronized void show() {

        PrintStreamps = null;

        try {

            ps = new PrintStream(new File("Test.txt"));

            for (int i = 0; i < 100; i++) {

                ps.append("这是" + Thread.currentThread().getName() + "输出的" + i + "\n");

            }

 

        }catch(IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }finally{

            ps.close();

        }

    }

 

    @Override

    public void run() {

        show();

    }

 

    public static void main(String[] args) {

        PrintProgrampp1= newPrintProgram();

        PrintProgrampp2= newPrintProgram();

        Threadt1 = new Thread(pp1);

        t1.setName("线程1");

        Threadt2 = new Thread(pp2);

        t2.setName("线程2");

        t1.start();

        t2.start();

    }

 

}

 

得到Test.txt中内容为:


但如果改为如下代码,则结果将不同:

package SyncronizedMenthodTest;

 

import java.io.File;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.io.PrintStream;

 

public classPrintProgram implements Runnable {

 

    public synchronized void show() {

        PrintStreamps = null;

        try {

            ps = new PrintStream(new File("Test.txt"));

            for (int i = 0; i < 100; i++) {

                ps.append("这是" + Thread.currentThread().getName() + "输出的" + i

                        +"\n");

            }

 

        }catch(IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }finally{

            ps.close();

        }

    }

 

    @Override

    public void run() {

        show();

    }

 

    public static void main(String[] args) {

        PrintProgrampp1 = newPrintProgram();

        Threadt1 = new Thread(pp1);

        t1.setName("线程1");

        t1.start();

        Threadt2 = new Thread(pp1);

        t2.setName("线程2");

        t2.start();

    }

 

}

结果如下:


因为这里的synchronized保护的是共享数据。t1,t2是同一个对象(pp1)的两个线程,当其中的一个线程(例如:t2)开始执行run()方法时,由于run()受synchronized保护,所以同一个对象的其他线程(t1)无法访问synchronized方法(run方法)。只有当 t2执行完后t1才有机会执行。

二、 Java模拟生产者消费者问题

         了解了Java的syncronized关键字,那么生产者消费者问题也迎刃而解了。例如题目如下:


解决方案:

---------------

产品

---------------

package ProducerAndConsumerProblem;

 

public classProduce {

 

    /*

     * 生产者生产的产品

     */

    private String name;

    private double price;

 

    @Override

    public String toString() {

        return "Produce [name="+ name+ ", price=" + price+ "]";

    }

 

    public Produce(String name, double price) {

        super();

        this.name = name;

        this.price = price;

    }

 

    public Produce() {

        super();

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public double getPrice() {

        return price;

    }

 

    public void setPrice(double price) {

        this.price = price;

    }

 

}

 

---------------

店员

---------------

package ProducerAndConsumerProblem;

 

public classClerk {

    // 店员用于存放生产者生产的产品,最多放20

    // 相当于一个缓冲区

    static final int n = 20;

    private static Produce[] produce = new Produce[n];

 

    private static int produceNumber= 0;

    static int inIndex = 0;

    static int outIndex = 0;

 

    private static Object obj = new Object();

 

    public static Produce getProduce(int index) {

        return produce[index];

    }

 

    public static void setProduce(Produce produce, int index) {

        Clerk.produce[index] = produce;

    }

 

    public static Object getObj() {

        return obj;

    }

 

    public static void setObj(Object obj) {

        Clerk.obj = obj;

    }

 

    public synchronized void addProduce() {

 

        if (produceNumber>= 20) {

            try {

                wait();

            }catch(InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }else{

            System.out.println(Thread.currentThread().getName()

                    +"生产了一个产品,放在店员" + inIndex+ "那儿");

            Produceproduce= newProduce();

            Clerk.setProduce(produce, inIndex);

            inIndex = (inIndex + 1) % n;

            produceNumber++;

            notifyAll();

        }

    }

 

    public synchronized void getProduce() {

        if (produceNumber<= 0) {

            try {

                wait();

            }catch(InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

        }else{

            System.out.println(Thread.currentThread().getName()+ ""

                    +outIndex+ "号店员那儿取走一件商品");

            Clerk.setProduce(null, outIndex);

            outIndex = (outIndex + 1) % n;

            produceNumber--;

            notifyAll();

        }

    }

 

}

---------------

生产者

---------------

package ProducerAndConsumerProblem;

 

public classProducer implementsRunnable {

 

    Clerkclerk=null;

 

    public Producer(Clerk clerk) {

        this.clerk = clerk;

    }

 

    @Override

    public void run() {

        while (true) {

            try {

                Thread.sleep(1000);

            }catch(InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            clerk.addProduce();

           

        }

    }

}

---------------

消费者

---------------

package ProducerAndConsumerProblem;

 

public classConsumer implementsRunnable {

 

    Clerkclerk= null;

 

    public Consumer(Clerk clerk) {

        this.clerk = clerk;

    }

 

    @Override

    public void run() {

        while (true) {

            try {

                Thread.sleep(1000);

            }catch(InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            clerk.getProduce();

        }

    }

 

}

---------------

主函数

---------------

package ProducerAndConsumerProblem;

 

public classTest {

    public static void main(String[] args) {

        Clerkclerk=new Clerk();

        Consumerconsumer= newConsumer(clerk);

        Threadt1 = new Thread(consumer);

        t1.setName("消费者");

        Producerproducer= newProducer(clerk);

        Threadt2 =new Thread(producer);

        t2.setName("生产者");

        t1.start();

        t2.start();

    }

}

---------------

显示结果

---------------


一、 课程设计目的 在多道程序环境下,进程同步问题十分重要,通过解决“生产者-消费者”问题,可以帮助我们更好的理解进程同步的概念及实现方法。掌握线程创建和终止的方法,加深对线程和进程概念的理解,会用同步与互斥方法实现线程之间的进行操作。 在学习操作系统课程的基础上,通过实践加深对进程同步的认识,同时,可以提高运用操作系统知识解决实际问题的能力;锻炼实际的编程能力、创新能力及团队组织、协作开发软件的能力;还能提高调查研究、查阅技术文献、资料以及编写软件设计文档的能力。 二、 课程设计内容 模拟仿真“生产者-消费者”问题的解决过程及方法。 三、 系统分析与设计 1、 系统分析 在OS中引入进程后,虽然提高了资源的利用率和系统的吞吐量,但由于进程的异步性,也会给系统造成混乱,尤其是在他们争用临界资源时。为了对多个相关进程在执行次序上进行协调,以使并发执行的诸程序之间能有效地共享资源和相互合作,使程序的执行具有可再现性,所以引入了进程同步的概念。信号量机制是一种卓有成效的进程同步工具。 在生产者---消费者问题中应注意(信号量名称以多个生产者和多个消费者中的为例):首先,在每个程序中用于互斥的wait(mutex)和signal(mutex)必须成对出现;其次,对资源信号量empty和full的wait和signal操作,同样需要成对地出现,但它们分别处于不同的程序中。生产者与消费者进程共享一个大小固定的缓冲区。其中,一个或多个生产者生产数据,并将生产的数据存入缓冲区,并有一个或多个消费者从缓冲区中取数据。 2、 系统设计: 系统的设计必须要体现进程之间的同步关系,所以本系统采用2个生产者、2个消费者 和20个缓冲区的框架体系设计。为了更能体现该系统进程之间的同步关系,系统的生产者、 消费者的速度应该可控,以更好更明显的表现出结果。 为了使本系统以更加简单、直观的形式把“消费者-生产者”问题表现出来,我选择了使 用可视化界面编程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值