`
landyer
  • 浏览: 141991 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

public class BlockingQueueTest { public static void main(String[] args) { Sca

    博客分类:
  • java
 
阅读更多

Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法了,而不能直接访问LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。BlockingQueue 继承了Queue接口。

 

队列是一种数据结构.它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素就是说,队列以一种先进先出的方式管理数据,如果你试图向一个已经满了的阻塞队列中添加一个元素或者是从一个空的阻塞队列中移除一个元索,将导致线程阻塞.在多线程进行合作时,阻塞队列是很有用的工具。工作者线程可以定期地把中间结果存到阻塞队列中而其他工作者线线程把中间结果取出并在将来修改它们。队列会自动平衡负载。如果第一个线程集运行得比第二个慢,则第二个线程集在等待结果时就会阻塞。如果第一个线程集运行得快,那么它将等待第二个线程集赶上来。下表显示了jdk1.5中的阻塞队列的操作:

 

add        增加一个元索                     如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常
element  返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常
offer       添加一个元素并返回true       如果队列已满,则返回false
poll         移除并返问队列头部的元素    如果队列为空,则返回null
peek       返回队列头部的元素             如果队列为空,则返回null
put         添加一个元素                      如果队列满,则阻塞
take        移除并返回队列头部的元素     如果队列为空,则阻塞

 

remove、element、offer 、poll、peek 其实是属于Queue接口。 

 

阻塞队列的操作可以根据它们的响应方式分为以下三类:aad、removee和element操作在你试图为一个已满的队列增加元素或从空队列取得元素时抛出异常。当然,在多线程程序中,队列在任何时间都可能变成满的或空的,所以你可能想使用offer、poll、peek方法。这些方法在无法完成任务时只是给出一个出错示而不会抛出异常。

 

注意:poll和peek方法出错进返回null。因此,向队列中插入null值是不合法的。

 

还有带超时的offer和poll方法变种,例如,下面的调用:
boolean success = q.offer(x,100,TimeUnit.MILLISECONDS);
尝试在100毫秒内向队列尾部插入一个元素。如果成功,立即返回true;否则,当到达超时进,返回false。同样地,调用:
Object head = q.poll(100, TimeUnit.MILLISECONDS);
如果在100毫秒内成功地移除了队列头元素,则立即返回头元素;否则在到达超时时,返回null。

 

最后,我们有阻塞操作put和take。put方法在队列满时阻塞,take方法在队列空时阻塞。

 

java.ulil.concurrent包提供了阻塞队列的4个变种。默认情况下,LinkedBlockingQueue的容量是没有上限的(说的不准确,在不指定时容量为Integer.MAX_VALUE,不要然的话在put时怎么会受阻呢),但是也可以选择指定其最大容量,它是基于链表的队列,此队列按 FIFO(先进先出)排序元素。


ArrayBlockingQueue在构造时需要指定容量,并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来达到这种公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队列,此队列按 FIFO(先进先出)原则对元素进行排序。


PriorityBlockingQueue是一个带优先级的队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限(看了一下源码,PriorityBlockingQueue是对PriorityQueue的再次包装,是基于堆数据结构的,而PriorityQueue是没有容量限制的,与ArrayList一样,所以在优先阻塞队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError),但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元素要具有比较能力。


最后,DelayQueue(基于PriorityQueue来实现的)是一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。 下面是延迟接口:

public interface Delayed extends Comparable<Delayed> {
     long getDelay(TimeUnit unit);
}

 

放入DelayQueue的元素还将要实现compareTo方法,DelayQueue使用这个来为元素排序。

 

下面的实例展示了如何使用阻塞队列来控制线程集。程序在一个目录及它的所有子目录下搜索所有文件,打印出包含指定关键字的文件列表。从下面实例可以看出,使用阻塞队列两个显著的好处就是:多线程操作共同的队列时不需要额外的同步,另外就是队列会自动平衡负载,即那边(生产与消费两边)处理快了就会被阻塞掉,从而减少两边的处理速度差距。下面是具体实现:

 

public class BlockingQueueTest {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		System.out.print("Enter base directory (e.g. /usr/local/jdk5.0/src): ");
		String directory = in.nextLine();
		System.out.print("Enter keyword (e.g. volatile): ");
		String keyword = in.nextLine();

		final int FILE_QUEUE_SIZE = 10;// 阻塞队列大小
		final int SEARCH_THREADS = 100;// 关键字搜索线程个数

		// 基于ArrayBlockingQueue的阻塞队列
		BlockingQueue<File> queue = new ArrayBlockingQueue<File>(
				FILE_QUEUE_SIZE);

		//只启动一个线程来搜索目录
		FileEnumerationTask enumerator = new FileEnumerationTask(queue,
				new File(directory));
		new Thread(enumerator).start();
		
		//启动100个线程用来在文件中搜索指定的关键字
		for (int i = 1; i <= SEARCH_THREADS; i++)
			new Thread(new SearchTask(queue, keyword)).start();
	}
}
class FileEnumerationTask implements Runnable {
	//哑元文件对象,放在阻塞队列最后,用来标示文件已被遍历完
	public static File DUMMY = new File("");

	private BlockingQueue<File> queue;
	private File startingDirectory;

	public FileEnumerationTask(BlockingQueue<File> queue, File startingDirectory) {
		this.queue = queue;
		this.startingDirectory = startingDirectory;
	}

	public void run() {
		try {
			enumerate(startingDirectory);
			queue.put(DUMMY);//执行到这里说明指定的目录下文件已被遍历完
		} catch (InterruptedException e) {
		}
	}

	// 将指定目录下的所有文件以File对象的形式放入阻塞队列中
	public void enumerate(File directory) throws InterruptedException {
		File[] files = directory.listFiles();
		for (File file : files) {
			if (file.isDirectory())
				enumerate(file);
			else
				//将元素放入队尾,如果队列满,则阻塞
				queue.put(file);
		}
	}
}
class SearchTask implements Runnable {
	private BlockingQueue<File> queue;
	private String keyword;

	public SearchTask(BlockingQueue<File> queue, String keyword) {
		this.queue = queue;
		this.keyword = keyword;
	}

	public void run() {
		try {
			boolean done = false;
			while (!done) {
				//取出队首元素,如果队列为空,则阻塞
				File file = queue.take();
				if (file == FileEnumerationTask.DUMMY) {
					//取出来后重新放入,好让其他线程读到它时也很快的结束
					queue.put(file);
					done = true;
				} else
					search(file);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
		}
	}
	public void search(File file) throws IOException {
		Scanner in = new Scanner(new FileInputStream(file));
		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);
		}
		in.close();
	}
}
 

 

 

 

 

分享到:
评论

相关推荐

    飞机大战java源码

    public static void main String args[] throws InterruptedException { MainFrame mainFrame; try { mainFrame new MainFrame ; mainFrame loadGame ; } catch Exception e { e printStackTrace ; } }...

    java开发飞机大战(可运行)

    public static void main String args[] throws InterruptedException { MainFrame mainFrame; try { mainFram e new MainFrame ; mainFrame loadGame ; } catch Exception e { e printStackTrace ; } } }...

    C#中static void Main(string[] args) 参数示例详解

    static void Main(string[] args) { Console.WriteLine(Hello World!); Console.ReadLine(); } } } static:是将Main方法声明为静态, 是应用程序的入口。 void:说明main方法不会返回任何内容。 string[]...

    JAVA习题及实验-电子工业大学出版!

    2. `public static void main(String args[])` 是Java程序的入口点,程序从这里开始执行。 3. `int i=1, n=10, s=0;` 分别声明并初始化了三个整型变量,`i`作为循环计数器,`n`为要累加到的数,`s`用于存储累加的...

    import java.io.*; public class FirstPart{ public static void main(String[] args) throws Exception{ System.out.print("The input Fahrenheit is "); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int f = Integer.parseInt(br.re

    public static void main(String[] args) throws Exception{ System.out.print("The input Fahrenheit is "); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int f = Integer....

    SCJP Braindump SCJP 题库 SCJP 考题

    public static void main(String[] args) { try { return; } finally { System.out.println("Finally"); } } } ``` - **问题:** 运行结果是什么? - **答案解析:** - `finally`块在方法返回之前总是被执行...

    Java经典算法20题

    public static void main(String[] args) { for (int i = 1; i ; i++) { System.out.println(fibonacci(i)); } } public static int fibonacci(int n) { if (n == 1 || n == 2) { return 1; } else { ...

    《JavaSE知识点阶段考试题》试题和答案以及答题卡

    C、public static void main(String args) D、public static void main(String args[]) 2、下列哪个是JDK提供的编译器( )。 A、java.exe B、javac.exe C、javap.exe D、javaw.exe 3、下列那个可以作为...

    一款java2c加固混淆工具 java转c 交叉编译.dll.so

    MYJ2C将编译的Java方法转换为C语言。... public static void main(String args[]) { System.out.println("Hello, world!"); } } After public class App { public static native void main(String args[]); }

    jv程序设计习题.docx

    public class abc { public static void main(String args [ ]) { AB s = new AB("Hello!","I love JAVA."); } } class AB { String s1; String s2; public AB(String str1, String str2) { s1 = str1; s2 = str2; ...

    圆柱体积,用java代码

    public static void main String[] args { System out print &quot;Enter the radius and length of a cylinder:&quot; ; Scanner input new Scanner System in ; float radius input nextFloat ; float ...

    java笔试题目

    public static void main(String[] args) { Other o = new Other(); new Something().addOne(o); } public void addOne(final Other o) { o.i++; } } class Other { public int i; } ``` **解析**: - ...

    java的倒序排列

    public static void main(String[] args) { String s = "abcdefg"; String t = ""; char[] charArray = s.toCharArray(); for (int i = charArray.length-1; i&gt;=0; i--){ t=t+charArray[i]; } ...

    Java编程代码

    源代码说明Java程序设计... public static void main(String[] args) { int a=155; float b=21.0f; System.out.println("a="+a+",b="+b); //输出a,b的值 System.out.println("a/b="+(a/b)); //输出a/b的值 } }

    Java语言程序设计资料:java题库PDF

    public static void main(String args[]){ /*---- ------*/ } System.out.println("Programming in Java is fun!"); 程序填空。 在屏幕上显示如下网格。 +---+---+ +---+---+ import java.io.*; public class Test...

    myj2c java混淆工具

    MYJ2C是一款Java混淆工具,将编译好的... public static void main(String args[]) { System.out.println("Hello, world!"); } } 编译后 public class App { public static native void main(String args[]); }

    实例分析Java中public static void main(String args[])是什么意思

    Java中的`public static void main(String[] args)`是每个可独立执行的Java程序的入口点,它的每一个部分都有特定的含义: 1. `public`:这是一个访问修饰符,表示该方法可以被任何其他类访问,无论它们是否在同一...

    1000以内质数的输出

    public static void main String [] args { String str &quot;&quot;; for int i 1; i &lt; 1000; i++ { for a 2; a &lt; int i 2; a++ { if i % a 0 { break; } } if a &gt; int i 2 { str+ String ...

    static、this、super、final的JAVA用法

    Java 中的静态方法使用 static 关键字来修饰,例如 public static void main(String[] args)。静态方法通常用于提供一些实用工具给应用程序中的其他类使用。在 Java 的类库中大量的静态方法正是出于此目的而定义的。...

Global site tag (gtag.js) - Google Analytics