标签:
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();
}
}
---------------
显示结果
---------------
标签:
原文地址:http://blog.csdn.net/zydirtyfish/article/details/43278479