多线程:阻塞队列

java.util.concurrent包中的BlockingQueue可以安全地从一个线程向另一个线程传递数据。生产者线程向队列插入元素,消费者线程则取出它们。

当试图向队列添加元素而队列满,或想从队列移出元素而队列空,阻塞队列导致线程阻塞。

阻塞队列方法

方法 正常动作 特殊情况下动作
put 添加一个元素 若队列满,则阻塞
take 移出并返回头元素 若队列空,则阻塞
offer 添加一个元素并返回true 若队列满,则返回false
poll 移出并返回头元素 若队列空,则返回null
peek 返回头元素 若队列空,则返回null
add 添加一个元素 若队列满,则抛出IllegalStateException异常
remove 移出并返回头元素 若队列空,则抛出NoSuchElementException异常
element 返回头元素 若队列空,则抛出NoSuchElementException异常
  • 将队列当作线程管理工具,对应使用put和take方法
  • 在一个多线程程序中,队列会在任何时候空或满,一定要使用offer、poll和peek方法,因为add、remove和element会抛出异常。
  • poll和peek返回空来指示失败,所以队列不允许插入null
  1. ArrayBlockingQueue构造时需要指定容量,并有一个可选参数来指定是否需要公平性。若设置公平参数,等待最长时间的线程会优先得到处理。公平性通常会降低性能。
  2. LinkedBlockingQueue容量没有上界,也可以指定最大容量
  3. LinkedBlockingDueue双端队列
  4. PriorityBlockingQueue优先级队列,按照优先级顺序被移出
  5. DelayQueue当延迟时间结束时才能移出元素

使用阻塞队列控制一组线程。程序在一个目录及它所有子目录下搜索所有文件,打印包含指定关键字的行。

public class BlockingQueueTest {
	private static final int FILE_QUEUE_SIZE = 10;
	private static final int SEARCH_THREADS = 100;
	private static final File DUMMY = new File("");
	private static BlockingQueue<File> queue = new ArrayBlockingQueue<>(FILE_QUEUE_SIZE);

	public static void main(String[] args) {
		try (Scanner in = new Scanner(System.in)) {
			System.out.print("Enter base directory (e.g. /opt/jdk1.8.0/src): ");
			String directory = in.nextLine();
			System.out.print("Enter keyword (e.g. volatile): ");
			String keyword = in.nextLine();
		    
		    // 生产者
			Runnable enumerator = () -> {
				try {
					enumerate(new File(directory));
					queue.put(DUMMY); //表示队列空了
				} 
				catch (InterruptedException e) {
				}
			};
        	new Thread(enumerator).start();
        	
        	// 消费者
        	for (int i = 1; i <= SEARCH_THREADS; i++) {
        		Runnable searcher = () -> {
        			try {
        				boolean done = false;
        				while (!done) {
        					File file = queue.take();
        					if (file == DUMMY) {
        						queue.put(file);
        						done = true;
        					} else {
        						search(file, keyword);
        					}
        				}
        			} 
        			catch (IOException e) {
        				e.printStackTrace();
        			}
        			catch (InterruptedException e) {
        			}
        		};
        		new Thread(searcher).start();
        	}
		}
	}
	
	// 列举目录下所有文件和子目录
	public static void enumerate(File directory) throws InterruptedException {
		File[] files = directory.listFiles();
		for (File file : files) {
			if (file.isDirectory())
				enumerate(file);
			else
				queue.put(file); 
		}
	}

	// 搜索指定文件中的关键字并打印所在行
	public static void search(File file, String keyword) throws IOException {
		try (Scanner in = new Scanner(file, "UTF-8")) {
			int lineNumber = 0;
			while (in.hasNextLine()) {
				lineNumber++;
				String line = in.nextLine();
				if (line.contains(keyword)) {
					System.out.printf("%s:%d:%s%n", file.getPath(), lineNumber, line);
				}
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/baidu_25104885/article/details/88625457