Java中的并发库学习总结(二)

2014-11-24 02:01:30 · 作者: · 浏览: 1
.concurrent.Semaphore; public class MySemaphore extends Thread { private Semaphore position; private int id; public MySemaphore(int i, Semaphore s) { this.id = i; this.position = s; } public void run() { try { //有没有空厕所 if (position.availablePermits() > 0) { System.out.println("顾客[" + this.id + "]进入厕所,有空位"); }else { System.out.println("顾客[" + this.id + "]进入厕所,没空位,排队"); } //获取到空厕所了 position.acquire(); System.out.println("顾客[" + this.id + "]获得坑位"); //使用中... Thread.sleep((int) (Math.random() * 1000)); System.out.println("顾客[" + this.id + "]使用完毕"); //厕所使用完之后释放 position.release(); }catch (Exception e) { e.printStackTrace(); } } public static void main(String args[]) { ExecutorService list = Executors.newCachedThreadPool(); Semaphore position = new Semaphore(2);//只有两个厕所 //有十个人 for (int i = 0; i < 10; i++) { list.submit(new MySemaphore(i + 1, position)); } list.shutdown(); position.acquireUninterruptibly(2); System.out.println("使用完毕,需要清扫了"); position.release(2); } }

ReentrantLock

一个可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大。他们两个的区别见:http://blog.csdn.net/fw0124/article/details/6672522
ReentrantLock 将由最近成功获得锁定,并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。
此类的构造方法接受一个可选的公平参数。
当设置为 true时,在多个线程的争用下,这些锁定倾向于将访问权授予等待时间最长的线程。否则此锁定将无法保证任何特定访问顺序。
与采用默认设置(使用不公平锁定)相比,使用公平锁定的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁定和保证锁定分配的均衡性时差异较小。不过要注意的是,公平锁定不能保证线程调度的公平性。因此,使用公平锁定的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁定时。还要注意的是,未定时的 tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁定是可用的,此方法就可以获得成功。
建议总是 立即实践,使用 try 块来调用 lock,在之前/之后的构造中,最典型的代码如下:
class X {
	private final ReentrantLock lock = new ReentrantLock();
	// ...
	public void m() {
		lock.lock(); // block until condition holds
		try {
			// ... method body
		}finally {
			lock.unlock()
		}
	}
}

我的例子:
import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.locks.ReentrantLock;

public class MyReentrantLock extends Thread {

	TestReentrantLock lock;
	private int id;

	public MyReentrantLock(int i, TestReentrantLock test) {
		this.id = i;
		this.lock = test;
	}

	public void run() {
		lock.print(id);
	}

	public static void main(String args[]) {
		ExecutorService service = Executors.newCachedThreadPool();
		TestReentrantLock lock = new TestReentrantLock();
		for (int i = 0; i < 10; i++) {
			service.submit(new MyReentrantLock(i, lock));
		}
		service.shutdown();
	}

}

class TestReentrantLock {
	private ReentrantLock lock = new ReentrantLock();
	public void print(int str) {
		try {
			lock.lock();
			System.out.println(str + "获得");
			Thread.sleep((int) (Math.random() * 1000));
		}catch (Exception e) {
			e.printStackTrace();
		}finally {
			System.out.println(str + "释放");
			lock.unlock();
		}
	}

}

BlockingQueue

支持两个附加操作的 Queue,这两个操作是:检索元素时等待队列变为非空,以及存储元素时等待空间变得可用。
BlockingQueue 不接受 null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException。null 被用作指示 poll 操作失败的警戒值。
BlockingQueue 可以是限定容量的。它在任意给定时间都可以有一个 remainingCapacity,超出此容量,便无法无阻塞地 put 额外的元素。
没有任何内部容量约束的 BlockingQueue 总是报告 Integer.MAX_VALUE 的剩余容量。
BlockingQueue 实现主要用于生产者-使用者队列,但它另外还支持 Collection 接口。因此,举例来说,使用 remove(x) 从队列中移除任意一个元素是有可能的。
然而,这种操作通常不 会有效执行,只能有计划地偶尔使用,比如在取消排队信息时。
BlockingQueue 实现是线程安全的。所有排队方法都可以使用内部锁定或其他形式的并发控制来自动达到它们的目的。
然而,大量的 Collection 操作(addAll、containsAll、retainAll 和 removeAll)没有 必要自动执行,除非在实现中特别说明。
因此,举例来说,在只添加了 c 中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。
BlockingQueue 实质上不 支持使用任何一种“close”或“shutdown”操作来指示不再添加任何项。
这种功能的需求和使用有依赖于实现的倾向。例如,一种常用的策略是:对于生产者,插入特殊的 end-of-stream 或 poison 对象,并根据使用者获取这些对象的时间来对它们进行解释。
下面的例子演示了这个阻塞队列的基本功能。

import java.util.concurrent.BlockingQueue;

import java.uti