关于java:Java并发程序设计总览学习

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 定律

充分利用存储空间等计算资源,尽量增大问题规模以产生更好/更准确的解。