1、应用线程的一些教训
-
设置名称
无论何种形式,启动一个线程,就要给它一个名字!这对排错诊断系统监控有帮忙。否则诊断问题时,无奈直观晓得某个线程的用处。
-
响应中断
程序应该对线程中断作出失当的响应。
-
应用ThreadLocal
它的功能非常简单,就是为每一个应用该变量的线程都提供一个变量值的正本,是每一个线程都能够独立地扭转本人的正本,而不会和其它线程的正本抵触。从线程的角度看,就如同每一个线程都齐全领有该变量。
留神:应用ThreadLocal,个别都是申明在动态变量中,如果一直的创立ThreadLocal而且没有调用其remove办法,将会导致内存泄露。
2、Executor :ExecutorService和Future
为了不便并发执行工作,呈现了一种专门用来执行工作的实现,也就是Executor。由此,工作提交者不须要再创立治理线程,应用更不便,也缩小了开销。
java.util.concurrent.Executors是Executor的工厂类,通过Executors能够创立你所须要的Executor。
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Object> task = new Callable < Object > () {
public Object call () throws Exception {
Object result = "...";
return result;
}
} ;
Future<Object> future = executor.submit(task);
future.get();
有两种工作:Runnable、Callable,Callable是须要返回值的工作。
Task Submitter把工作提交给Executor执行,他们之间须要一种通信伎俩,这种伎俩的具体实现,通常叫做Future。Future通常包含get(阻塞至工作实现),cancel,get(timeout)(期待一段时间)等等。Future也用于异步变同步的场景。
3、阻塞队列: put和take、offer和poll、drainTo
阻塞队列,是一种罕用的并发数据结构,罕用于生产者-消费者模式。
在Java中,有三种罕用的阻塞队列:
ArrayBlockingQueue
LinkedBlockingQueue
SynchronousQueue
应用阻塞队列:
Monitor的实践模型
4、ReentrantLock和Synchronized
Synchronized是Lock的一种简化实现,一个Lock能够对应多个Condition,而synchronized把Lock和Condition合并了,一个synchronizedLock只对应一个Condition,能够说Synchronized是Lock的简化版本。
在JDK5,Synchronized要比Lock慢很多,然而在JDK6中,它们的效率差不多。
5、Lock-free算法
LockFree算法,不须要加锁。
通常都是三个局部组成:
①循环
②CAS (CompareAndSet)
③break
进一步应用Lock-Free数据结构
class BeanManager {
private ConcurrentMap<String, Object> map = new ConcurrentHashMap<String, Object>();
public Object getBean
(String key) {
Object bean = map.get(key);
if (bean == null) {
map.putIfAbsent(key, createBean());
bean = map.get(key);
}
return bean;
}
}
ConcurrentHashMap并没有实现Lock-Free,只是应用了拆散锁的方法使得可能反对多个Writer并发。ConcurrentHashMap须要应用更多的内存。
同样的思路用于更新数据库-乐观锁。
Lock-Free算法,能够说是乐观锁,如果非强烈竞争的时候,不须要应用锁,从而开销更小,速度更快。
适当应用CopyOnWriteArrayList,可能进步读操作时的效率。
6、对于锁应用的教训介绍
应用反对CAS的数据结构,防止应用锁,如:AtomicXXX、ConcurrentMap、CopyOnWriteList、ConcurrentLinkedQueue
肯定要应用锁的时候,留神取得锁的程序,相同程序取得锁,就容易产生死锁。
死锁常常是无奈完全避免的,鸵鸟策略被很多根底框架所采纳。
通过Dump线程的StackTrace,例如linux下执行命令kill -3 <pid>,或者jstack–l <pid>,或者应用Jconsole连贯下来查看线程的StackTrace,由此来诊断死锁问题。
内部锁常被忽视而导致死锁,例如数据库的锁
7、并发流程管制伎俩:CountDownlatch、Barrier
并发流程管制-应用CoutDownLatch
final int COUNT = 10;
final CountDownLatch completeLatch = new CountDownLatch(COUNT);
for (int i = 0; i < COUNT; ++i) {
Thread thread = new Thread("worker thread " + i) {
public void run() {
// do xxxx
completeLatch.countDown();
}
};
thread.start();
}
// 当你启动了一个线程,你须要等它执行完结,此时,CountDownLatch兴许是一个很好的抉择。
completeLatch.await();
final CountDownLatch startLatch = new CountDownLatch(1);
for (int i = 0; i < 10; ++i) {
Thread thread = new Thread("worker thread " + i) {
public void run() {
try {
// 当你启动很多线程,你须要这些线程等到告诉后才真正开始,CountDownLatch兴许是一个很好的抉择。
startLatch.await();
} catch (InterruptedException e) {
return;
}
// do xxxx
}
};
thread.start();
}
// do xxx
startLatch.countDown();
Barrier:
屏障是一种协调机制(一种算法),它迫使参加并发(或分布式)算法的过程期待,直到它们中的每一个都达到其程序中的某个点。这些协调点的汇合被称为屏障。一旦所有流程都达到了阻碍,它们都能够持续通过阻碍。
8、定时器
应用定时器ScheduledExecutorService
java.util.concurrent.Executors是ScheduledExecutorService的工厂类,通过Executors,你能够创立你所须要的ScheduledExecutorService。
JDK 1.5之后有了ScheduledExecutorService,不倡议你再应用java.util.Timer,因为它无论性能性能都不如ScheduledExecutorService。
大规模定时器TimerWheel
存在一种算法TimerWheel,实用于大规模的定时器实现。这个算法最早是被设计用来实现BSD 内核中定时器的,起初被宽泛移植到诸如ACE 等框架中,堪称BSD 中经典算法之一,能针对定时器的各类常见操作提供靠近常数工夫的响应,且能依据须要很容易进行扩大。
9、并发三大定律:Amdahl、Gustafson、Sun-Ni
Amdahl 定律
Gene Amdahl 发现在计算机体系架构设计过程中,某个部件的优化对整个架构的优化和改善是有下限的。这个发现起初成为出名的Amdahl 定律。
Gustafson 定律
Gustafson假如随着处理器个数的减少,并行与串行的计算总量也是能够减少的。Gustafson定律认为减速系数简直跟处理器个数成正比,如果现实情况合乎Gustafson定律的假如前提的话,那么软件的性能将能够随着解决个数的减少而减少。
Sun-Ni 定律
充分利用存储空间等计算资源,尽量增大问题规模以产生更好/更准确的解。