接上一篇《java并发编程(三)客户端加锁与组合》
最近事太多,耽误了两天时间没有写博客,感觉每天不记录下自己的学习东西就想没学一样,这两天的事实在太多,不管是学业上的 还是感情上的,闹心,程序员还是把踏入爱河的事放一放吧~对了 最近接了一本《HTTP权威指南》,想深入学习下,赶紧把Java 并发访问的相关知识 总结完成就开始,另外,在某米音乐的朋友 说 java web 已经很难找工作了,现在是php的天下了,心里一颤,然后继续学习java,你懂的,好了不扯了,继续今天的内容。
java提供了很多的同步工具类,简化了编程过程,而且减少了bug,当然我们完全可以自己写同步工具类,但是 我们不是说好的 要站在巨人的肩膀上 编程的吗。
CountDownLatch
public long timeTasks(int nThread, final Runnable task)
throws InterruptedException {
final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(nThread);
for (int i = 0; i < nThread; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
startGate.await();
try {
task.run();
} finally {
endGate.countDown();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
task.run();
}
}).start();
}
long start = System.nanoTime();
startGate.countDown();
endGate.await();
long end = System.nanoTime();
return end - start;
}
FutureTask
public class PreLoader {
private final FutureTask<ProductInfo> future = new FutureTask<ProductInfo>(
new Callable<ProductInfo>() {
@Override
public ProductInfo call() throws Exception {
return loaderProductInfo();
}
});
private final Thread thread = new Thread(future);
public void start() {
thread.start();
}
public ProductInfo get() throws DataLoadException, InterruptedException {
try {
return future.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof DataLoadException)
throw (DataLoadException) cause;
else
throw launderThrowable(cause);
}
}
private static RuntimeException launderThrowable(Throwable t) {
if (t instanceof RuntimeException)
return (RuntimeException) t;
else if (t instanceof Error)
throw (Error) t;
else
throw new IllegalStateException("Not unchecked ", t);
}
ProductInfo loaderProductInfo() {
// 耗时事件
return null;
}
}
PreLoader 类创建了一个FutureTask,当程序需要ProductInfo时,可以调用get方法,如果数据已经加载,立即返回,否则将等待加载完成后返回。
Semaphore
public class BoundedHash<T> {
private final Set<T> set;
private final Semaphore sem;
public BoundedHash(int permits) {
set = Collections.synchronizedSet(new HashSet<T>());
sem = new Semaphore(permits);
}
public boolean add(T t) throws InterruptedException {
sem.acquire();
boolean wasAdded = false;
try {
wasAdded = set.add(t);
return wasAdded;
} finally {
if (!wasAdded)
sem.release();
}
}
public boolean remove(T t) {
boolean wasRemoved = set.remove(t);
if (wasRemoved)
sem.release();
return wasRemoved;
}
}
CyclicBarrier
public class CellularAutomata {
private final Board mainBoard;
private final CyclicBarrier barrier;
private final Worker[] workers;
public CellularAutomata(Board board) {
this.mainBoard = board;
int count = Runtime.getRuntime().availableProcessors();
this.barrier = new CyclicBarrier(count, new Runnable() {
@Override
public void run() {
}
});
this.workers = new Worker[count];
for (int i = 0; i < count; i++) {
workers[i] = new Worker(mainBoard.getSubBoard(count, i));
}
}
private class Worker implements Runnable {
private final Board board;
public Worker(Board board) {
this.board = board;
}
@Override
public void run() {
while (!board.hasConvergeted()) {
for (int i = 0; i < board.getMaxx(); i++)
for (int j = 0; j < board.getMaxy(); j++)
board.setNewValue(i, j, computeValue(i, j));
try {
barrier.await(); //等待 直到达到线程数
} catch (InterruptedException | BrokenBarrierException e) {
return;
}
}
}
}
public void start() {
for (int i = 0; i < workers.length; i++) {
new Thread(workers[i]).start();
mainBoard.waitForConvergence();
}
}
}
构造高效且可伸缩的结果缓存
interface Computable<K, V> {
V compute(K arg) throws InterruptedException;
}
public class Memoizer<K, V> implements Computable<K, V> {
private final Map<K, Future<V>> cache = new ConcurrentHashMap<K, Future<V>>();
private final Computable<K, V> c;
public Memoizer(Computable<K, V> c) {
this.c = c;
}
@Override
public V compute(K arg) throws InterruptedException {
while (true) {
Future<V> f = cache.get(arg);
if (f == null) {
Callable<V> eval = new Callable<V>() {
@Override
public V call() throws Exception {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
f = cache.put(arg, ft);
if (f == null) {
f = ft;
ft.run();
}
}
try {
return f.get();
} catch (CancellationException e) {
cache.remove(arg, f);
} catch (ExecutionException e) {
throw new InterruptedException();
}
}
}
}
认真分析这个例子,设计的很巧妙。
基础部分总结:
-
It’s the mutable state, stupid.1
All concurrency issues boil down to coordinating access to mutablestate. The less mutable state, the easier it is to ensure thread safety.
-
Make fields final unless they need to be mutable.
-
Immutable objects are automatically thread-safe.
Immutable objects simplify concurrent programming tremendously.They are simpler and safer, and can be shared freely without lockingor defensive copying.
-
Encapsulation makes it practical to manage the complexity.
You could write a thread-safe program with all data stored in globalvariables, but why would you want to? Encapsulating data withinobjects makes it easier to preserve their invariants; encapsulatingsynchronization within objects makes it easier to comply with theirsynchronization policy.
-
Guard each mutable variable with a lock.
-
Guard all variables in an invariant with the same lock.
-
Hold locks for the duration of compound actions.
-
A program that accesses a mutable variable from multiple threadswithout synchronization is a broken program.
-
Don’t rely on clever reasoning about why you don’t need to synchro-nize.
-
Include thread safety in the design process—or explicitly documentthat your class is not thread-safe.
-
Document your synchronization policy.
- 可变状态是至关重要的
- 尽量将域生命为final类型,除非需要它们是可变的。
- 不可变对象一定是线程安全的。
- 封装有助于管理复杂性
- 用锁来保护每个可变对象。
- 当保护同一个不变性条件中的所有变量时,要使用同一个锁。
- 在执行符合操作期间,要持有锁。
- 如果从多个线程中访问同一个可变变量时没有同步机制,那么程序会出现问题。
- 不要故作聪明的推断出不需要使用同步。
- 在设计过程中考虑线程安全,或者在文档中明确地指出不是线程安全的。
- 将同步策略文档化。