论坛首页 Java企业应用论坛

一道面试题

浏览 16077 次
锁定老帖子 主题:一道面试题
精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2013-10-08  
编写一段生产者/消费者的Java代码,其中生产者每次生产1个0到1000之间的随机数,消费者则把该随机数打印出来。如果产生的随机数为0,则生产者、消费者均退出运行。要求生产者、消费者均使用线程来实现。如题,线程基本的我也会,但是像这样有点复杂的还真不会,求大家帮我啊
   发表时间:2013-10-09  
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Test {
	private static List<Integer> memory = new ArrayList<Integer>();
	private static boolean flag = true;
	private static int memoryLength;
	public static void main(String[] args) {
		Thread thread_product = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("product-start");
				while (flag) {
					int num = new Random().nextInt(1000);
					memory.add(num);
					if(num == 0){
						flag = false;
					}
				}
				System.out.println("product-complete");
			}
		},"thread-product");
		
		Thread thread_client = new Thread(new Runnable() {
			@Override
			public void run() {
				while (flag || memory.size() != memoryLength) {
					if(flag && memory.size()==memoryLength){
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					System.out.println("client:"+memory.get(memoryLength++));
				}
				System.out.println("client-complete");
			}
		},"thread-client");
		thread_product.start();
		thread_client.start();
	}
}


这样行吗?
0 请登录后投票
   发表时间:2013-10-09  
xiangyaoan 写道
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Test {
	private static List<Integer> memory = new ArrayList<Integer>();
	private static boolean flag = true;
                ...
		},"thread-client");
		thread_product.start();
		thread_client.start();
	}
}


这样行吗?


很不幸,你的代码没有考虑同步问题
0 请登录后投票
   发表时间:2013-10-09  
为什么要重复造车轮,不直接使用java.util.concurrent.BlockingQueue?
0 请登录后投票
   发表时间:2013-10-09  
OpenMind 写道
为什么要重复造车轮,不直接使用java.util.concurrent.BlockingQueue?

对,直接使用ArrayBlockingQueue或者LinkedBlockingQueue
0 请登录后投票
   发表时间:2013-10-09  
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class BlockingQueueTest {
	private static String FLAG="99";
	
	public static class Basket {
		// 篮子,能够容纳1000个数字
		BlockingQueue<String> basket = new LinkedBlockingQueue<String>(1000);
		
		// 生产数字,放入篮子
		public String produce() throws InterruptedException {
			int num = new Random().nextInt(1000);   
			System.out.println("++放入篮子中一个数字:"+num );
			basket.put(num+"");
			return num+"";
		}

		// 消费数字,从篮子中取走
		public String consume() throws InterruptedException {
			String num=basket.take();
			System.out.println("--取出篮子中一个数字:"+num );
			return num;
		}
		
	}
	

	//  测试方法
	public static void testBasket() {
		final Basket basket = new Basket();
		// 定义生产者
		class Producer implements Runnable {
			public void run() {
				try {
					while (true) {
						if(basket.produce().equals(FLAG)){
							System.out.println("!成功生产正确数字:"+FLAG);
							break;
						}
						// 休眠300ms
						Thread.sleep(300);
					}
				} catch (InterruptedException ex) {
				}
			}
		}

		// 定义数字消费者
		class Consumer implements Runnable {
			public void run() {
				try {
					while (true) {
						// 消费数字
						// 休眠1000ms
						if(basket.consume().equals(FLAG)){
							System.out.println("!成功获取正确数字:"+FLAG);
							break;
						}
						Thread.sleep(500);
					}
				} catch (InterruptedException ex) {
				}
			}
		}

		ExecutorService service = Executors.newCachedThreadPool();
		Producer producer = new Producer();
		Consumer consumer = new Consumer();
		service.submit(producer);
		service.submit(consumer);
		
		// 程序运行60s后,所有任务停止
		try {
			Thread.sleep(60*1000);
		} catch (InterruptedException e) {
		}

		
		service.shutdownNow();
	}

	public static void main(String[] args) {
		BlockingQueueTest.testBasket();
	}
}

 

0 请登录后投票
   发表时间:2013-10-09   最后修改:2013-10-09
给出一个更贴近考题细节的答案。
几点注意: 1. 消费生产者模式原则上讲究生产一个产品后就不能再生产,要等消费完才能生产第二个。因此可以选用SynchronousQueue。当然广义上的消费生产者,用BlockingQueue旗下的任意一个实现类都可以。
2.逻辑很简单,一个线程往queue里存(put),一个线程从queue里取(take)。put和take都是阻塞型的方法,防止while循环死命的循环下去。
3. 随机出0后,producer和consumer都必须停止,如果不用threadpool工具来做,单纯用thread来实现,就要注意,让thread在合适的时候return。比如生产者随机到0时,return并且依然把0存入queue,消费者取出0时,线程return。

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;

public class Test {

	BlockingQueue<Integer> queue = new SynchronousQueue<Integer>();

	Random rd = new Random();

	class Producer extends Thread {
		@Override
		public void run() {
			while (true) {
				int number = rd.nextInt(1000);
				System.out.println("Producer Generate : " + number);
				try {
					queue.put(number);
					if (number == 0) {
						System.out.println("Producer stoped.");
						return;
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}

	}

	class Consumer extends Thread {
		@Override
		public void run() {
			while (true) {
				try {
					if (queue.take() == 0) {
						System.out.println("Consumer stoped.");
						return;
					}
					;
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public void startTest() {
		Producer producer = new Producer();
		Consumer consumer = new Consumer();
		producer.start();
		consumer.start();
	}

	public static void main(String[] args) {
		new Test().startTest();
	}
}
0 请登录后投票
   发表时间:2013-10-09  
OpenMind 写道
为什么要重复造车轮,不直接使用java.util.concurrent.BlockingQueue?

为什么要重复造车轮,不直接使用java.util.concurrent.BlockingQueue?
0 请登录后投票
   发表时间:2013-10-09  
谢谢各位的回复,昨天有位师傅指导,我也写了个
package cn.yxw.test;

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ThreadTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Storage storage = new Storage();
		new Producer(storage).start();
		new Customer(storage).start();

	}

}

class Customer extends Thread {

	private Storage storage;

	public Customer(Storage storage) {
		this.storage = storage;
	}

	public void run() {
		while (true) {
			try {
				if (Storage.NUM == 0) {
					System.out.println("打印:" + 0 + ",线程终止");
					break;
				}
				Integer num = storage.print();
				System.out.println("打印:" + num);
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

class Producer extends Thread {

	private Storage storage;

	public Producer(Storage storage) {
		this.storage = storage;
	}

	public void run() {

		while (true) {

			try {
				Integer num = new Random().nextInt(1000);
				Storage.NUM = num;
				if (Storage.NUM == 0) {
					System.out.println("生产:" + 0 + ",线程终止");
					break;
				}
				storage.put(num);
				System.out.println("生产:" + num);
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}

	}
}

class Storage {
	private BlockingQueue<Integer> randomData = new ArrayBlockingQueue<Integer>(
			1);// 空间大小为1的阻塞队列

	public static int NUM = -1;

	public void put(Integer number) {

		try {
			randomData.put(number);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	public int print() {
		try {
			Integer number = randomData.take();
			return number;
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return 0;
	}
}
0 请登录后投票
   发表时间:2013-10-09  
恩,看了一下,我和你的代码逻辑基本是一样的。
另外,两点拙见:
一个是// 空间大小为1的阻塞队列,其实就是SynchronousQueue,jdk为这个特性量身定做的数据结构。ArrayQueue往往用来做缓存队列。
另一个就是建议Random实例放在全局,只需一个,不然每次循环都new一次,内存有点浪费
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics