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();

    }

}

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

显示结果

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值