Java并发编程实战 第5章 基础构建模块

委托是创建线程安全类的一个最有效的策略:只需让现有的线程安全类管理所有的状态即可。

5.1 同步容器类

如果不希望在迭代期间对容器加锁,那么一种替代方案就是克隆容器,并在副本上进行迭代。由于副本被封闭在线程内,因此其他线程不会在迭代期间对其修改。
容器的toString、hashCode、equals方法都隐含了迭代操作

5.2 并发容器

同步容器将对容器状态的访问都串行化,以实现线程安全性,这会严重降低并发性,吞吐量降低。

5.2.1 ConcurrentHashMap

并发下实现更高的吞吐量,单线程环境中损失较小的性能。

5.2.3 CopyOnWriteArrayList

写入时复制
每次修改时,都会创建并重新发布一个新的容器副本。修改时会复制底层数组,开销较大。适用于仅当迭代操作远远多于修改操作时。

5.3 阻塞队列和生产者-消费者模式

在构建高可靠的应用程序时,有界队列是一种强大的资源管理工具:它们能抑制并防止产生过多的工作项,使应用程序在负荷过载的情况下变得更加健壮。
BlockingQueue实现:
1、FIFO:LinkedBlockingQueue,ArrayBlockingQueue
2、优先级:PriorityBlockingQueue,可以实现对象的comparable方法,也可以使用Comparator比较器。
3、同步队列,SynchronousQueue,没有维护存储空间,维护一组线程。put和take会一直阻塞,直到有另一个线程已经准备好参与到交付过程。适用有足够多的消费者,并且总是有一个消费者准备获取交付的工作。

5.3.2 串行线程封闭

同步机制保证对象从生产者线程安全的发布到消费者线程。

5.3.3 双端队列与工作密取

一个消费者完成了自己双端队列中的工作,那么take已从其他消费者双端队列的末尾秘密地获取工作。

5.4 阻塞方法与中断方法

当某方法跑出InterruptedException时,表示该方法是一个阻塞方法,如果这个方法被中断,那么它将努力提前结束阻塞状态。
方法对中断请求的响应度越高,就越容易及时取消执行时间很长的操作。

5.5 同步工具类

5.5.1 闭锁

可以延迟线程的进度直到其到达终止状态。在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有的线程通过。这样可以确保某些活动直到其他活动都完成后才继续执行。
CountDownLatch,闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown方法递减计数器,表示有一个事件已经发生了,而await方法等待计数器达到零,这表示所有需要等待的事件都已经发生。如果计数器的值非零,那么await会一直阻塞知道计数器为零,或者等待中的线程中断,或者等待超时。

public class Test {
	public long timeTask(int n, final Runnable task) throw InterruptedException {
		final CountDownLatch startGate = new CountDownLatch(1);
		final CountDownLatch endGate = new CountDownLatch(n);
		for (int i = 0; i < n; ++i) {
			Thread t = new Thread() {
			      public void run() {
			      	     try {
			      	     	startGate.await();
			      	     	try {
			      	     		task.run();
			      	     	}
			      	     	final {
			      	     		endGate.countDown();
			      	     	}
			      	     } 
			      	     catch(InterruptedException e) {
			      	     }
			      }
			}
			t.start();
		}
	}
	long start = System.nanoTime();
	startGate.countDown();
	endGate.await();
	long end = System.nanoTime();
	return end - start;
}

5.5.2 FutureTask

FutureTask表示的计算是通过Callable来实现的,相当于一种可生成结果的Runnable。
Future.get的行为取决于任务的状态。如果任务已经完成,那么get会立即返回结果,否则get将阻塞知道任务进入完成状态,然后返回结果或者抛出异常。
FutureTask将计算结果从执行计算的线程传递到获取这个结果的线程,而FutureTask的规范确保了这种传递过程能实现结果的安全发布。
FutureTask在Executor框架中表示异步任务。

5.5.3 信号量

Semaphore可用于实现资源池,例如数据库连接池。可以构造一个固定长度的资源池,当池为空时,请求资源将会失败,当你真正希望看到的行为是阻塞而不是失败,并当池非空时解除阻塞。

5.5.4 栅栏

闭锁是一次性对象,一旦进入终止状态,就不能被重置。
Barrier类似于闭锁,他能阻塞一组线程知道某个时间发生。关键区别在于,所有线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。
CyclicBarrier可以使一定数量的参与方反复地在栅栏位置汇集,在并行迭代算法中非常有用。

5.6 构建高效且可伸缩的结果缓存

你可能感兴趣的:(并发编程)