SlideShare a Scribd company logo
1 of 16
Download to read offline
Java 并发核心编程
内容涉及:
1、关于 java 并发
2、概念
3、保护共享数据
4、并发集合类
5 线程
6、线程协作及其他




1、关于 java 并发
自从 java 创建以来就已经支持并发的理念,如线程和锁。这篇指南主要是为帮助 java 多线
程开发人员理解并发的核心概念以及如何应用 这些理念。本文的主题是关于具有 java 语言
风格的 Thread、synchronized、volatile,以及 J2SE5 中新增的概念,如锁 (Lock)、原子性
(Atomics)、并发集合类、线程协作摘要、Executors。开发者通过这些基础的接口可以构建高
并发、线程安全的 java 应用程序。




2、概念
本部分描述的 java 并发概念在这篇 DZone Refard 会被通篇使用。
从 JVM 并发看 CPU 内存指令重排序(Memory
Reordering):http://kenwublog.com/illustrate-memory-reordering-in-cpu
java 内存模型详解: http://kenwublog.com/explain-java-memory-model-in-detail
概念                    描述
Java Memory Model     在 JavaSE5(JSR133)中定义的 Java Memory Model(JMM)是为
Java 内存模型             了确保当编写并发代码的时候能够提供 Java 程序员一个可用的
                      JVM 实现。术语 JMM 的作用类似与一个观察同步读写字段 的
                      monitor。它按照“happens-before order(先行发生排序) ”的顺序—
                      可以解释为什么一个线程可以获得其他线程的结果,                这组成了一个
                      属性同步的程序,使字段具有不变性,以及其他属性。
monitor               Java 语言中,每个对象都拥有一个访问代码关键部分并防止其他对
Monitor               象访问这段代码的“monitor”        (每个对象都拥有一个对代码关键部
                      分 提 供 访 问 互 斥 功 能 的 “ monitor ” 。 这 段 关 键 部 分 是 使 用
                                                       )
                      synchronized 对 方 法 或 者 代 码 标 注 实 现 的 。 同 一 时 间 在 同 一 个
                      monitor 中,只允许一个线程运行代码的任意关键部分。当一个线
程试图获取代码的关键部分时,如果这段代码的 monitor 被其他线
                    程拥有,那么这个线程会无限期的等待这个 monitor 直到它被其他
                    线程释放。除了访问互斥之外,monitor 还可以通过 wait 和 notify
                    来实现协作。
原子字段赋值              除了 doubles 和 longs 之外的类型,给一个这些类型的字段赋值是
Atomic field        一个原子操作。在 JVM 中,doubles 和 longs 的更新是被实现为 2
assignment          个独立的操作,     因此理论上可能会有其他的线程得到一个部分更新
                    的结果。为了保护共享的 doubles 和 longs,可以使用 volatile 标记
                    这个字段或者在 synchronized 修饰的代码块中操作字段。
竞争状态                竞争发生在当不少于一个线程对一个共享的资源进行一系列的操
Race condition      作,如果这些线程的操作的顺序不同,会导致多种可能的结果。
数据竞争                数 据 竞 争 主 要 发 生 在 多 个 线 程 访 问 一 个 共 享 的 、 non-final 、
Data race           non-volatile、没有合适的 synchronization 限制的字段。Java 内存模
                    型不会对这种非同步的数据访问提供任何的保证。                 在不同的架构和
                    机器中数据竞争会导致不可预测的行为。
安全发布                在一个对象创建完成之前就发布它的引用时非常危险的。  避免这种
Safe publications   使用这种引用的一种方法就是在创建期间注册一个回调接口。  另外
                    一种不安全的情况就是在构造子中启动一个线程。在这 2 种情况中,
                    非完全创建的对象对于其他线程来说都是可见的。
不可变字段               不可变字段在对象创建之后必须明确设定一个值,                否则编译器就会
Final Fields        报出一个错误。      一旦设定值后,   不可变字段的值就不可以再次改变。
                    将一个对象的引用设定为不可变字段并不能阻止这个对象的改变。
                    例如,ArrayList 类型的不可变字段不能改变为其他 ArrayList 实例
                    的引用,但是可以在这个 list 实例中添加或者删除对象。
                         在创建结尾,对象会遇到”final field freeze”:如果对象被安全的
                    发布后,即使在没有 synchronization 关键字修饰的情况下,也能保
                    证所有的线程获取 final 字段在构建过程中设定的值。 final field
                    freezer 不仅对 final 字段有用,而且作用于 final 对象中的可访问属
                    性。
不可变对象               在语法上 final 字段能够创建不需要 synchronization 修饰的、能够
Immutable objects   被共享读取的线程安全的不可变对象。实现 Immutable Object 需要
                    保证如下条件:
                    ·对象被安全的发布(在创建过程中 this 引用是无法避免的)
                    ·所有字段被声明为 final
                    ·在创建之后,在对象字段能够被访问的范围中是不允许修改这个
                    字段的。
                    ·class 被声明为 final(为了防止 subclass 违反这些规则)
3、保护共享数据
编写线程安全的 java 程序,当修改共享数据的时候要求开发人员使用合适的锁来保护数据。
锁能够建立符合 Java Memory Model 要求的访问顺序,而且确保其他线程知道数据的变化。
注意:
  在 Java Memory Model 中,如果没有被 synchronization 修饰,改变数据不需要什么特别的
语法表示。JVM 能够自由地重置指令顺序的特性和对可见性的限制方式很容易让开发人员
感到奇怪。




3.1、Synchronized
3.1、

每个对象实例都拥有一个每次只能让一个线程锁住的 monitor。        synchronized 能够用在一个方
法或者代码块中来锁住这个 monitor。用 synchronized 修饰一个对象,当修改这个对象的一
个字段,synchronized 保证其他线程余下的对这个对象的读操作能够获取修改后的值。需要
注意的是修改同步块之外的数据或者 synchronized 没有修饰当前被修改的对象,那么不能保
证其他线程读到这些最新的数据。synchronized 关键字能够修饰一个对象实例中的函数或者
代码块。在一个非静态方法中 this 关键字表示当前的实例对象。在一个 synchronized 修饰的
静态的方法中,这个方法所在的类使用 Class 作为实例对象。




3.2、Lock
3.2、

Java.util.concurrent.locks 包中有个标准 Lock 接口。ReentrantLock 实现了 Lock 接口,它完全
拥有 synchronized 的特性,同时还提供了新的功能:获取 Lock 的状态、非阻塞获取锁的方
法 tryLock()、可中断 Lock。
下面是使用 ReentrantLock 的详细示例:
public class Counter{
   private final Lock lock = new ReentrantLock();
   private int value;
   public int increment() {
      lock.lock();
      try {
          return ++value;
        finally
        finally{
      }finally
          lock.unlock();
      }
   }
}
3.3、ReadWriteLock
3.3、

Java.util.concurrent.locks 包中还有个 ReadWriteLock 接口(实现类是
ReentrantWriteReadLock)    ,它定义一对锁:读锁和写锁,特征是能够被并发的读取但每次只
能有一个写操作。使用 ReentrantReadWriteLock 并发读取特性的详细示例:
public class ReadWrite {
   private     final    ReadWriteLock     lock    =    new
ReentrantReadWriteLock();
   private int value;
   public void increment(){
      lock.writeLock().lock();
      try
      try{
          value++;
        finally
        finally{
      }finally
          lock.writeLock().unlock();
      }
   }
   public int current(){
      lock.readLock().lock();
      try
      try{
          return value;
        finally
        finally{
      }finally
          lock.readLock().unlock();
      }
   }
}



3.4、volatile
3.4、

volatile 原理与技巧: http://kenwublog.com/the-theory-of-volatile
volatile 修饰符用来标注一个字段,表明任何对这个字段的修改都必须能被其他随后访问的
线程获取到,这个修饰符和同步无关。因此,volatile 修饰的数据的可见性和 synchronization
类似,但是这个它只作用于对字段的读或写操作。在 JavaSE5 之前,因为 JVM 的架构和实
现的原因,不同 JVM 的 volatile 效果是不同的而且也是不可信的。下面是 Java 内存模型明
确地定义 volatile 的行为:
public class Processor implements Runnable {
   private volatile boolean stop;
   public void stopProcessing(){
      stop = true
             true;
   }
   public void run() {
      while (!stop) {
//do processing
        }
    }
}
注意:使用 volatile 修饰一个数组并不能让这个数组的每个元素拥有 volatile 特性,           这种声明
只是让这个数组的 reference 具有 volatile 属性。数组被声明为 AtomicIntegerArray 类型,则
能够拥有类似 volatile 的特性。


3.5、原子类
3.5、原子类

使用 volatile 的一个缺点是它能够保证数据的可见性,却不能在一个原子操作中对 volatile
修饰的字段同时进行校验和更新操作。      java.util.concurrent.atomic 包中有一系列支持在单个非
锁定(lock)的变量上进行原子操作的类,类似于 volatile。示例:
public class Counter{
   private AtomicInteger value = new AtomicInteger();
   private int value;
   public int increment() {
      return value.incrementAndGet();
   }
}
incrementAndGet 方法是原子类的复合操作的一个示例。booleans, integers, longs, object
references, integers 数组, longs 数组, object references 数组 都有相应的原子类。




3.6、ThreadLocal
3.6、

通过 ThreadLocal 能数据保存在一个线程中,而且不需要 lock 同步。理论上 ThreadLocal 可
以让一个变量在每个线程都有一个副本。       ThreadLocal 常用来屏蔽线程的私有变量, “并
                                                   例如
发事务”或者其他的资源。而且,它还被用来维护每个线程的计数器,统计,或者 ID 生成
器。
public class TransactionManager {
   private static final ThreadLocal<Transaction>
currentTransaction
      = new ThreadLocal<Transaction>() {
      @Override
      protected Transaction initialValue() {
         return new NullTransaction();
      }
   };
   public Transaction currentTransaction() {
      Transaction current = currentTransaction.get();
      if
      if(current.isNull()) {
         current = new TransactionImpl();
currentTransaction.put(current);
         }
         return current;
    }
}




4、Concurrent Collections
  Concurrent Collections(并发集合类)
保护共享数据的一个关键技术是在存储数据的类中封装同步机制。    所有对数据的使用都要经
过同步机制的确认使这个技术能够避免数据的不当访问。在 java.util.concurrent 包中有很多
为并发使用情况下设计的数据结构。通常,使用这些数据结构比使用同步包装器装饰的非同
步的集合的效率更高。


4.1、Concurrent lists and sets
4.1、

在 Table2 中列出了 java.util.concurrent 包中拥有的 3 个并发的 List 和 Set 实现类。
类                       描述
CopyOnWriteArraySet     CopyOnWriteArraySet 在语意上提供写时复制(copy-on-werite)的特
                        性,对这个集合的每次修改都需要对当前数据结构新建一个副本,
                        因此写操作发费很大。在迭代器创建的时候,会对当前数据数据结
                        构创建一个快照用于迭代。
CopyOnWriteArrayList    CopyOnWriteArrayList 和 CopyOnWriteArraySet 类似,也是基于
                        copy-on-write 语义实现了 List 接口
ConcurrentSkipListSet   ConcurrentSkipListSet(在 JavaSE 6 新增的)提供的功能类似于
                        TreeSet,能够并发的访问有序的 set。因为 ConcurrentSkipListSet 是
                        基于“跳跃列表(skip list)       ”实现的,只要多个线程没有同时修改
                        集合的同一个部分,那么在正常读、写集合的操作中不会出现竞争
                        现象。
skip list: http://blog.csdn.net/yuanyufei/archive/2007/02/14/1509937.aspx
            http://zh.wikipedia.org/zh-cn/%E8%B7%B3%E8%B7%83%E5%88%97%E8%A1%A8




4.2、Concurrent maps
4.2、

Java.util.concurrent 包中有个继承 Map 接口的 ConcurrentMap 的接口,ConcurrentMap 提供了
一些新的方法(表 3)           。所有的这些方法在一个原子操作中各自提供了一套操作步骤。如果
将每套步骤在放在 map 之外单独实现,在非原子操作的多线程访问的情况下会导致资源竞
争。
表 3:ConcurrentMap 的方法:
方法                                描述
putIfAbsent(K key, V value) : V   如果 key 在 map 中不存在,则把 key-value 键值对放入 map
                                  中,否则不执行任何操作。返回值为原来的 value,如果 key
                                  不存在 map 中则返回 null
remove(Object key, Object         如果 map 中有这个 key 及相应的 value,那么移除这对数据,
value) : boolean                  否则不执行任何操作
replace (K key, V value) : V      如果 map 中有这个 key,那么用新的 value 替换原来的 value,
                                  否则不执行任何操作
replace (K key, V oldValue, V     如果 map 中有这对 key-oldValue 数据,那么用 newValue 替
newValue) : boolean               换原来的 oldValue,否则不执行任何操作
在表 4 中列出的是 ConcurrentMap 的 2 个实现类
方法                                描述
ConcurrentHashMap                 ConcurrentHashMap 提供了 2 种级别的内部哈希方法。第一
                                  种级别是选择一个内部的 Segment,第二种是在选定的
                                  Segment 中将数据哈希到 buckets 中。第一种方法通过并行
                                  地在不同的 Segment 上进行读写操作来实现并发。
                                  (ConcurrentHashMap 是引入了 Segment,每个 Segment 又是
                                  一个 hash 表,ConcurrentHashMap 相当于是两级 Hash 表,
                                  然后锁是在 Segment 一级进行的,提高了并发性。
                                  http://mooncui.javaeye.com/blog/380884
                                  http://www.javaeye.com/topic/344876
                                  )
ConcurrentSkipListMap             ConcurrentSkipListMap(JavaSE 6 新增的类)功能类似
                                  TreeMap,是能够被并发访问的排序 map。尽管能够被多线
                                  程正常的读写---只要这些线程没有同时修改 map 的同一个
                                  部分,ConcurrentSkipListMap 的性能指标和 TreeMap 差不
                                  多。




4.3、Queues
4.3、

Queues 类似于沟通“生产者”和“消费者”的管道。组件从管道的一端放入,然后从另一
端取出:      “先进先出”(FIFO)的顺序。Queue 接口在 JavaSE5 新添加到 java.util 中的,能够被
用于单线程访问的场景中,主要适用于多个生产者、一个或多个消费者的情景,所有的读写
操作都是基于同一个队列。
java.util.concurrent 包中的 BlockingQueue 接口是 Queue 的子接口,而且还添加了新的特性处
理如下场景:队列满(此时刚好有一个生产者要加入一个新的组件)                         、队列空(此时刚好有
一个消费者读取或者删除一个组件) BlockingQueue 提供如下方案解决这些情况:
                                  。                          一直阻塞
等待直到其他线程修改队列的数据状态;阻塞一段时间之后返回,如果在这段时间内有其他
线程修改队列数据,那么也会返回。
表 5:Queue 和 BlockingQueue 的方法:
方法                  策略                 插入           移除            核查
Queue               抛出异常               add          remove        element
返回特定的值         offer              poll                 peek
Blocking Queue     一直阻塞           put                take                 n/a
                   超时阻塞           offer              poll                 n/a
在 JDK 中提供了一些 Queue 的实现,在表 6 中是这些实现类的关系列表。
方法                           描述
PriorityQueue                PriorityQueue 是唯一一个非线程安全的队列实现类,用于单
                             线程存放数据并且将数据排序。
CurrentLinkedQueue           一个无界的、基于链接列表的、唯一一个线程安全的队列实
                             现类,不支持 BlockingQueue。
ArrayBlockingQueue           一个有界的、基于数组的阻塞队列。
LinkedBlockingQueue          一个有界的、基于链接列表的阻塞队列。有可能是最常用的
                             队列实现。
PriorityBlockingQueue        一个无界的、   基于堆的阻塞队列。
                                              队列根据设置的 Comparator
                             (比较器)来确定组件读取、移除的顺序(不是队列默认的
                             FIFO 顺序)
DelayQueue                   一个无界的、延迟元素(每个延迟元素都会有相应的延迟时
                             间值)的阻塞队列实现。只有在延时期过了之后,元素才能
                             被移除,而且最先被移除的是延时最先到期的元素。
SynchronousQueue             一种 0 容量的队列实现,生产者添加元素之后必须等待消费
                             者移除后才可以返回,反之依然。如果生产者和消费者 2 个
                             线程同时访问,那么参数直接从生产者传递到消费者。经常
                             用于线程之间的数据传输。




4.4、Deque
4.4、

在 JavaSE6 中新增加了两端都可以添加和删除的队列-Deque (发音"deck",not "dick"). Deques
不仅可以从一端添加元素,从另一端移除,而且两端都可以添加和删除元素。如 同
BlockingQueue,BlockingDeque 接口也为阻塞等待和超时等待的特殊情况提供了解决方法。
因为 Deque 继承 Queue、   BlockingDeque 继承 BlockingQueue,下表中的方法都是可以使用的:
接口        头或尾           策略                插入                移除            核查
Queue     Head          抛出异常              addFirst          removeFirst   getFirst
                        返回特定的值            offerFirst        pollFirst     peekFirst
          Tail          抛出异常              addLast           removeLast    getLast
                        返回特定的值            offerLast         pollLast      peekLast
Blockin   Head          一直阻塞              putFirst          takeFirst     n/a
gQueue                  超时阻塞              offerFirst        pollFirst     n/a
          Tail          一直阻塞              putLast           takeLast      n/a
                        超时阻塞              offerLast         pollLast      n/a


Deque 的一个特殊应用场景是只在一个端口进行添加、                删除、检查操作--堆栈(first-in-last-out
顺序)。Deque 接口提供了 stack 相同的方法:push(), pop()和 peek(),这方法和 addFirst(),
removeFirst(), peekFirst()一一对应,可以把 Deque 的任何一个实现类当做堆栈使用。表 6 中
是 JDK 中 Deque 和 BlockingDeque 的实现。注意 Deque 继承 Queue,BlockingDeque 继承自
BlockingQueue。
表 8:Deques
类                                         描述
LinkedList                                这个经常被用到的类在 JavaSE6 中有了新的
                                          改进-实现了 Deque 接口。在 LinkedList 中,
                                          可以使用标准的 Deque 方法来添加或者删除
                                          list 两端的元素。LinkedList 还可以被当做一
                                          个非同步的堆栈,用来替代同步的 Stack 类
ArrayDeque                                一个非同步的、支持无限队列长度(根据需
                                          要动态扩展队列的长度)的 Deque 实现类
LinkedBlockingDeque                       LinkeBlockingDeque 是 Deque 实现中唯一支
                                          持并发的、基于链接列表、队列长度可选的
                                          类。



5、线程
在 Java 中,java.lang.Thread 类是用来代表一个应用或者 JVM 线程。代码是在某个线程类的
上下文环境中执行的(使用 Thread.currentThread()来获取当前运行的线程)   。


5.1、线程通讯
5.1、线程通讯

线程之间最简单的通讯方式是一个线程直接调用另一个线程对象的方法。 9 中列出的是线
                                表
程之间可以直接交互的方法。
表 9:线程协作方法
线程方法                             描述
start                            启动一个线程实例,并且执行它的 run() 方法。
join                             一直阻塞直到其他线程退出
interrupt                        中断其他线程。线程如果在一个方法中被阻塞,会对
                                 interrupt 操作做出回应,并在这个方法执行的线程中抛出
                                 InterruptedException 异常;否则线程的中断状态被设定。
stop, suspend, resume, destroy   这些方法都被废弃,      不应该再使用了。因为线程处理过程中
                                 状态问题会导致危险的操作。相反,应该使用 interrupt() 或
                                 者 volatile 标示来告诉一个线程应该做什么。




5.2、"未捕获异常"处理器
5.2、 未捕获异常"

线程能够指定一个 UncaughtExceptionHandler 来接收任何一个导致线程非正常突然终止的未
捕获异常的通知。
Thread t = new Thread(runnable);
                                  new
   t.setUncaughtExceptionHandler(new
Thread.UncaughtExceptionHandler() {
      public void uncaughtException(Thread t, Throwable
e) {
         // TODO get Logger and log uncaught exception
      }
   });
   t.start();




5.3、死锁
5.3、死锁

当存在多个线程(最少 2 个)等待对方占有的资源,就会形成资源循环依赖和线程等待,                          产
生死锁。最常见的导致死锁的资源是对象 monitor,同时其他阻塞操作(例如 wait/notify)也
能导致死锁。
很多新的 JVM 能够检测 Monitor 死锁,并且可以将线程 dump 中由信号(中断信号)              、jstack
或者其他线程 dump 工具生成的死锁原因显示打印出来。
除了死锁,线程之间还会出现饥饿(starvation)和活锁(livelock). Starvation 是因为一个线程
长时间占有一个锁导致其他的线程一直处于等待状态无法进行下一步操作。                    Livelock 是因为
线程发费大量的时间来协调资源的访问或者检测避免死锁导致没有一个线程真正的干活。




6、线程协作

6.1、wait/notify
6.1、

wait/notify 关键字适用于一个线程通知另一个线程所需的条件状态已就绪,最常用于线程在
循环中休眠直到获取特定条件的场景. 例如,一个线程一直等待直到队列中有一个组件能够
处理;当组件添加到队列时,另一个线程能够通知这个等待的线程。
wait 和 notify 的经典用法是:

public class Latch {
   private final Object lock = new Object();
   private volatile boolean flag = false
                                   false;
   public void waitTillChange(){
      synchronized (lock) {
         while
         while(!flag){
            try {
               lock.wait();
} catch (InterruptedException e) {
               }
           }
       }
    }
    public void change(){
       synchronized (lock) {
          flag = true
                 true;
          lock.notifyAll();
       }
    }
}

在代码中需要注意的重要地方是:
� wait、notify、notifyAll 必须在 synchronized 修饰的代码块中执行,否则会在运行的时候
  抛出 IllegalMonitorStateException 异常
� 在循环语句 wait 的时候一定要设定循环的条件--这样能够避免 wait 开始之前,线程所
  需的条件已经被其他线程提供了却依然开始此线程 wait 导致的时间消耗。同时,这种
  办法还能够保证你的代码不被虚假的信息唤醒。
� 总是要保证在调用 notify 和 notifyAll 之前,能够提供符合线程退出等待的条件。否则
  会出现即使线程接收到通知信息,却不能退出循环等待的情况。


6.2、Condition
6.2、

在 JavaSE5 中新添加了 java.util.concurrent.locks.Condition 接口。Condition 不仅在 API 中实
现了 wait/notify 语义,而且提供了几个新的特性,例如:为每个 Lock 创建多重 Condition、
可中断的等待、访问统计信息等。Condition 是通过 Lock 示例产生的,示例:
public class LatchCondition {
   private final Lock lock = new ReentrantLock();
   private final Condition condition =
lock.newCondition();
   private volatile boolean flag = false
                                   false;

    public void waitTillChange(){
       lock.lock();
       try
       try{
           while
           while(!flag){
              try {
                 condition.await();
              } catch (InterruptedException e) {
              }
           }
         finally
         finally{
       }finally
           lock.unlock();
       }
    }
    public void change(){
       lock.lock();
       try
       try{
           flag = true
                   true;
           condition.notifyAll();
         finally
         finally{
       }finally
           lock.unlock();
       }
    }
}



6.3、Coordination classes
6.3、

java.util.concurrent 包中有几个类适用于常见的多线程通讯。 这几个协作类适用范围几乎涵盖
了使用 wait/notify 和 Condition 最常见的场景,而且更安全、更易于使用。

CyclicBarrier
在 CyclicBarrier 初始化的时候指定参与者的数量。参与者调用 awart()方法进入阻塞状态直
到参与者的个数达到指定数量,         此时最后一个到达的线程执行预定的屏障任务,    然后释放所
有的线程。屏障可以被重复的重置状态。常用于协调分组的线程的启动和停止。

CountDownLatch
需要指定一个计数才能初始化 CountDownLatch。线程调用 await()方法进入等待状态知道计
数变为 0。其他的线程(或者同一个线程)调用 countDown()来减少计数。如果计数变为 0
后是无法被重置的。常用于当确定数目的操作完成后,触发数量不定的线程。

Semaphore
Semaphore 维护一个“许可”集,能够使用 acquire()方法检测这个“许可”集,在“许可”
可用之前 Semaphore 会阻塞每个 acquire 访问。线程能够调用 release()来返回一个许可。当
Semaphore 只有一个“许可”的时候,可当做一个互斥锁来使用。

Exchanger
线程在 Exchanger 的 exchange()方法上进行交互、原子操作的方式交换数据。功能类似于数
据可以双向传递的 SynchronousQueue 加强版。



7、任务执行
很多 java 并发程序需要一个线程池来执行队列中的任务。在 java.util.concurrent 包中为这种
类型的任务管理提供了一种可靠的基本方法。


7.1、ExecutorService
7.1、

Executor 和易扩展的 ExecutorService 接口规定了用于执行任务的组件的标准。这些接口的使
用者可以通过一个标准的接口使用各种具有不同行为的实现类。

最通用的 Executor 接口只能访问这种类型的可执行(Runnable)任务 :
void execute(Runnable command)
Executor 子接口 ExecutorService 新加了方法,能够执行:Runnable 任务、Callable 任务以及
任务集合。
Future<?> submit(Runnable task)
Future<T> submit(Callable<T> task)
Future<T> submit(Runnable task, T result)
List<Future<T>> invokeAll (Collection<? extends Callable<T>> tasks)
List<Future<T>> invokeAll (Collection<? extends Callable<T>> tasks, long timeout, TimeUnit
unit)
T invokeAny(Collection<? extends Callable<T>> tasks)
T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)


7.2、Callable and Future
7.2、

Callable 类似于 Runnable,而且能够返回值、抛出异常:
� V call() throws Exception;
在一个任务执行框架中提交一个 Callable 任务,         然后返回一个 Future 结果是很常见的。
                                                         Future
表示在将来的某个时刻能够获取到结果。           Future 提供能够获取结果或者阻塞直到结果可用的
方法。任务运行之前或正在运行的时候,可以通过 Future 中的方法取消。
如果只是需要一个 Runnable 特性的 Future(例如在 Executor 执行)     ,可用使用 FutureTask。
FutureTask 实现了 Future 和 Runnable 接口,可用提交一个 Runnable 类型任务,然后在调用
部分使用这个 Future 类型的任务。


7.3、实现 ExecutorService
7.3、实现

ExecutorService 最主要的实现类是 ThreadPoolExecutor。这个实现类提供了大量的可配置特
性:
� 线程池--设定常用线程数量(启动前可选参数)和最大可用线程数量。
� 线程工厂--通过自定义的线程工厂生成线程,例如生成自定义线程名的线程。
� 工作队列--指定队列的实现类,实现类必须是阻塞的、可以是无界的或有界的。
� 被拒绝的任务--当队列已经满了或者是执行者不可用,需要为这些情况指定解决策略。
� 生命周期中的钩子--重写扩展在任务运行之前或之后的生命周期中的关键点
� 关闭--停止已接受的任务,等待正在运行的任务完成后,关闭 ThreadPoolExecutor。
ScheduledThreadPoolExecutor 是 ThreadPoolExecutor 的一个子类,能够按照定时的方式完成
任务(而不是 FIFO 方式)         。在 java.util.Timer 不是足够完善的情况下,
ScheduleThreadPoolExecutor 具有强大的可适用性。

Executors 类有很多静态方法(表 10)用于创建适用于各种常见情况的预先包装的
ExecutorService 和 ScheduleExecutorService 实例
表 10
方法                                 描述
newSingleThreadExecutor            创建只有一个线程的 ExecutorService
newFixedThreadPool                 返回拥有固定数量线程的 ExecutorService
newCachedThreadPool                返回一个线程数量可变的 ExecutorService
newSingleThreadScheduledExecutor   返回只有一个线程的
                                   ScheduledExecutorService
newScheduledThreadPool             创建拥有一组核心线程的
                                   ScheduledExecutorService


下面的例子是创建一个固定线程池,然后提交一个长期运行的任务:
int processors =
Runtime.getRuntime().availableProcessors();
     ExecutorService executor =
Executors.newFixedThreadPool(processors);
     Future<Integer> futureResult =
                new
executor.submit(new Callable<Integer>() {
        public Integer call() {
           //long time computation that returns an
Integer
           return null
                  null;
        }
     });
     Integer result = futureResult.get();


在这个示例中提交任务到 executor 之后,代码没有阻塞而是立即返回。在代码的最后一行调
用 get()方法会阻塞直到有结果返回。

ExecutorService 几乎涵盖了所有应该创建线程对象或线程池的情景。     在代码中需要直接创建
一个线程的时候,可以考虑通过 Executor 工厂创建的 ExecutorService 能否实现相同的目标;
这样做经常更简单、更灵活。

7.4、CompletionService
除了常见的线程池和输入队列模式,还有一种常见的情况:为后面的处理,每个任务生成的
结果必须积累下来。CompletionService 接口允许提交 Callable 和 Runnable 任务,而且还可
以从任务队列中获取这些结果:               (绿色部分和英文版不一样,已和作者确认,英文版将 take()
和 poll()方法混淆了)
� Future<V> take () -- 如果结果存在则获取,否则直接返回
� Future<V> poll () -- 阻塞直到结果可用
� Future<V> poll (long timeout, TimeUnit unit) -- 阻塞直到 timeout 时间结束
ExecutorCompletionService 是 CompletionService 的标准实现类。 ExecutorCompletionService
                                                          在
的构成函数中需要一个 Executor,ExecutorCompletionService 提供输入队列和线程池。




8、Hot Tip
  Hot
    热门信息:当设置线程池大小的时候,     最好是基于当前应用所运行的机器拥有的逻辑处
理器的数量。在 java 中,可用使用 Runtime.getRuntime().availableProcessors()获取这个值。
在 JVM 的生命周期中,可用处理器的数目是可变的。
9、关于作者
    Alex Miller 是 Terracotta Inc 公司 Java 集群开源产品的技术负责人, 曾在 BEA System 和
MetaMatrix 工作,是 MetaMatrix 的首席架构师。他对 Java、并发、分布式系统、查询语言
和软件设计感兴趣。他的 tweeter:@puredanger,blog:http://tect.puredanger.com,很喜欢在
用户组会议中发言。在 St. Louis,Alex 是 Lambda Lounge 小组的创建人,Lambda Lounge
用户组是为了学习、动态语言、Strange Loop 开发会议而创建的。




10
10、翻译后记
    开始阅读英文版的时候,并没有觉得文章中有什么晦涩的地方。但是在翻译之后,才发
现将文中的意思清楚地表达出来也是个脑力活,    有时一句话能够懂得意思,          却是很难用汉语
表达出来:  “只可意会,不可言传”--这也能解释我当年高中作文为啥每次只能拿 40 分(总
分 60)。在禅宗,师傅教弟子佛理,多靠弟子自身的明悟,故有当头棒喝、醍醐灌顶之说。
做翻译却不能这样,总不能让读者对着满篇的鸟文去琢磨明悟吧,须得直译、意译并用,                       梳
理文字。
    翻译也是一个学习的过程。阅读本文的时候会无意忽略自己以为不重要的词句,                 待到真
正翻译的时候,才发现自己一知半解、一窍不通,就只好 Google 之,翻译完成后,也学了
些知识,可谓是一箭双雕。
    个人精力所限,翻译中难免有不对的地方,望大家予以指正。
                       联系方式:MSN/E-Mail:nathanlhb@hotmail.com
                                Blog:http://blog.csdn.net/liu251

More Related Content

What's hot

千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7javatwo2011
 
Ecmascript
EcmascriptEcmascript
Ecmascriptjay li
 
JavaScript 教程
JavaScript 教程JavaScript 教程
JavaScript 教程Bobby Zhou
 
Java面试知识
Java面试知识Java面试知识
Java面试知识yiditushe
 
Spring 2.0 技術手冊第六章 - Hibernate 與 Spring
Spring 2.0 技術手冊第六章 - Hibernate 與 SpringSpring 2.0 技術手冊第六章 - Hibernate 與 Spring
Spring 2.0 技術手冊第六章 - Hibernate 與 SpringJustin Lin
 
Java多线程编程详解
Java多线程编程详解Java多线程编程详解
Java多线程编程详解yiditushe
 
潜力无限的编程语言Javascript
潜力无限的编程语言Javascript潜力无限的编程语言Javascript
潜力无限的编程语言Javascriptjay li
 
Spring中的object xml映射详解
Spring中的object xml映射详解Spring中的object xml映射详解
Spring中的object xml映射详解leeley2000
 
Java多线程设计模式
Java多线程设计模式Java多线程设计模式
Java多线程设计模式Tony Deng
 
Java并发编程培训
Java并发编程培训Java并发编程培训
Java并发编程培训dcshi
 
Spring 2.0 技術手冊第四章 - Spring AOP
Spring 2.0 技術手冊第四章 - Spring AOPSpring 2.0 技術手冊第四章 - Spring AOP
Spring 2.0 技術手冊第四章 - Spring AOPJustin Lin
 
Scala function-and-closures
Scala function-and-closuresScala function-and-closures
Scala function-and-closureswang hongjiang
 
第9章 t sql程序设计
第9章 t sql程序设计第9章 t sql程序设计
第9章 t sql程序设计hanmo1988
 
Spring 2.0 技術手冊第一章 - 認識 Spring
Spring 2.0 技術手冊第一章 - 認識 SpringSpring 2.0 技術手冊第一章 - 認識 Spring
Spring 2.0 技術手冊第一章 - 認識 SpringJustin Lin
 
Reactive X 响应式编程
Reactive X 响应式编程Reactive X 响应式编程
Reactive X 响应式编程Jun Liu
 
Inside.java.concurrency 35.thread pool.part8_future.scheduledthreadpoolexecutor
Inside.java.concurrency 35.thread pool.part8_future.scheduledthreadpoolexecutorInside.java.concurrency 35.thread pool.part8_future.scheduledthreadpoolexecutor
Inside.java.concurrency 35.thread pool.part8_future.scheduledthreadpoolexecutorAdy Liu
 

What's hot (20)

千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7
 
Sun java
Sun javaSun java
Sun java
 
Ecmascript
EcmascriptEcmascript
Ecmascript
 
JavaScript 教程
JavaScript 教程JavaScript 教程
JavaScript 教程
 
Java面试知识
Java面试知识Java面试知识
Java面试知识
 
Spring 2.0 技術手冊第六章 - Hibernate 與 Spring
Spring 2.0 技術手冊第六章 - Hibernate 與 SpringSpring 2.0 技術手冊第六章 - Hibernate 與 Spring
Spring 2.0 技術手冊第六章 - Hibernate 與 Spring
 
Js培训
Js培训Js培训
Js培训
 
Java多线程编程详解
Java多线程编程详解Java多线程编程详解
Java多线程编程详解
 
潜力无限的编程语言Javascript
潜力无限的编程语言Javascript潜力无限的编程语言Javascript
潜力无限的编程语言Javascript
 
sorting
sortingsorting
sorting
 
Spring中的object xml映射详解
Spring中的object xml映射详解Spring中的object xml映射详解
Spring中的object xml映射详解
 
Java多线程设计模式
Java多线程设计模式Java多线程设计模式
Java多线程设计模式
 
Java并发编程培训
Java并发编程培训Java并发编程培训
Java并发编程培训
 
Spring 2.0 技術手冊第四章 - Spring AOP
Spring 2.0 技術手冊第四章 - Spring AOPSpring 2.0 技術手冊第四章 - Spring AOP
Spring 2.0 技術手冊第四章 - Spring AOP
 
Scala function-and-closures
Scala function-and-closuresScala function-and-closures
Scala function-and-closures
 
functional-scala
functional-scalafunctional-scala
functional-scala
 
第9章 t sql程序设计
第9章 t sql程序设计第9章 t sql程序设计
第9章 t sql程序设计
 
Spring 2.0 技術手冊第一章 - 認識 Spring
Spring 2.0 技術手冊第一章 - 認識 SpringSpring 2.0 技術手冊第一章 - 認識 Spring
Spring 2.0 技術手冊第一章 - 認識 Spring
 
Reactive X 响应式编程
Reactive X 响应式编程Reactive X 响应式编程
Reactive X 响应式编程
 
Inside.java.concurrency 35.thread pool.part8_future.scheduledthreadpoolexecutor
Inside.java.concurrency 35.thread pool.part8_future.scheduledthreadpoolexecutorInside.java.concurrency 35.thread pool.part8_future.scheduledthreadpoolexecutor
Inside.java.concurrency 35.thread pool.part8_future.scheduledthreadpoolexecutor
 

Viewers also liked

MongoDB介绍
MongoDB介绍MongoDB介绍
MongoDB介绍popeast
 
Big Data Analytics Infrastructure
Big Data Analytics InfrastructureBig Data Analytics Infrastructure
Big Data Analytics InfrastructureMin Zhou
 
Message Queues for Web Applications
Message Queues for Web ApplicationsMessage Queues for Web Applications
Message Queues for Web ApplicationsGareth Rushgrove
 

Viewers also liked (6)

Scala
ScalaScala
Scala
 
Scala
ScalaScala
Scala
 
Golang
GolangGolang
Golang
 
MongoDB介绍
MongoDB介绍MongoDB介绍
MongoDB介绍
 
Big Data Analytics Infrastructure
Big Data Analytics InfrastructureBig Data Analytics Infrastructure
Big Data Analytics Infrastructure
 
Message Queues for Web Applications
Message Queues for Web ApplicationsMessage Queues for Web Applications
Message Queues for Web Applications
 

Similar to Java并发核心编程

Java面试32题
Java面试32题Java面试32题
Java面试32题yiditushe
 
Java相关基础知识
Java相关基础知识Java相关基础知识
Java相关基础知识yiditushe
 
线程与并发
线程与并发线程与并发
线程与并发Tony Deng
 
Java面试题集
Java面试题集Java面试题集
Java面试题集yiditushe
 
J2ee经典学习笔记
J2ee经典学习笔记J2ee经典学习笔记
J2ee经典学习笔记yiditushe
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题yiditushe
 
Java并发编程实践
Java并发编程实践Java并发编程实践
Java并发编程实践sharewind
 
Java面试笔试题大汇总
Java面试笔试题大汇总Java面试笔试题大汇总
Java面试笔试题大汇总yiditushe
 
IKVM.NET 深入敵營的 Java
IKVM.NET 深入敵營的 JavaIKVM.NET 深入敵營的 Java
IKVM.NET 深入敵營的 Java建興 王
 
第8章 运行时的存储管理
第8章 运行时的存储管理第8章 运行时的存储管理
第8章 运行时的存储管理tjpucompiler
 
大公司的Java面试题集
大公司的Java面试题集大公司的Java面试题集
大公司的Java面试题集yiditushe
 
Java程序员面试之葵花宝典
Java程序员面试之葵花宝典Java程序员面试之葵花宝典
Java程序员面试之葵花宝典yiditushe
 
Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作zhubin885
 
Java 面试32问
Java 面试32问Java 面试32问
Java 面试32问yiditushe
 
JVM内容管理和垃圾回收
JVM内容管理和垃圾回收JVM内容管理和垃圾回收
JVM内容管理和垃圾回收Tony Deng
 
Row Set初步学习V1.1
Row Set初步学习V1.1Row Set初步学习V1.1
Row Set初步学习V1.1Zianed Hou
 
线程编程方面
线程编程方面线程编程方面
线程编程方面yiditushe
 
并发编程交流
并发编程交流并发编程交流
并发编程交流bluedavy lin
 

Similar to Java并发核心编程 (20)

Java面试32题
Java面试32题Java面试32题
Java面试32题
 
Java相关基础知识
Java相关基础知识Java相关基础知识
Java相关基础知识
 
线程与并发
线程与并发线程与并发
线程与并发
 
Java面试题集
Java面试题集Java面试题集
Java面试题集
 
J2ee经典学习笔记
J2ee经典学习笔记J2ee经典学习笔记
J2ee经典学习笔记
 
Java华为面试题
Java华为面试题Java华为面试题
Java华为面试题
 
Java并发编程实践
Java并发编程实践Java并发编程实践
Java并发编程实践
 
Java面试笔试题大汇总
Java面试笔试题大汇总Java面试笔试题大汇总
Java面试笔试题大汇总
 
IKVM.NET 深入敵營的 Java
IKVM.NET 深入敵營的 JavaIKVM.NET 深入敵營的 Java
IKVM.NET 深入敵營的 Java
 
Exodus2 大局观
Exodus2 大局观Exodus2 大局观
Exodus2 大局观
 
第8章 运行时的存储管理
第8章 运行时的存储管理第8章 运行时的存储管理
第8章 运行时的存储管理
 
大公司的Java面试题集
大公司的Java面试题集大公司的Java面试题集
大公司的Java面试题集
 
Java程序员面试之葵花宝典
Java程序员面试之葵花宝典Java程序员面试之葵花宝典
Java程序员面试之葵花宝典
 
Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作
 
Java 面试32问
Java 面试32问Java 面试32问
Java 面试32问
 
SCJP ch17
SCJP ch17SCJP ch17
SCJP ch17
 
JVM内容管理和垃圾回收
JVM内容管理和垃圾回收JVM内容管理和垃圾回收
JVM内容管理和垃圾回收
 
Row Set初步学习V1.1
Row Set初步学习V1.1Row Set初步学习V1.1
Row Set初步学习V1.1
 
线程编程方面
线程编程方面线程编程方面
线程编程方面
 
并发编程交流
并发编程交流并发编程交流
并发编程交流
 

More from wavefly

The comet technology on Jetty
The comet technology on Jetty The comet technology on Jetty
The comet technology on Jetty wavefly
 
Jetty(version 8)核心架构解析
Jetty(version 8)核心架构解析Jetty(version 8)核心架构解析
Jetty(version 8)核心架构解析wavefly
 
Head first in xmemcached yanf4j
Head first in xmemcached yanf4jHead first in xmemcached yanf4j
Head first in xmemcached yanf4jwavefly
 
Rpc原理与实现
Rpc原理与实现Rpc原理与实现
Rpc原理与实现wavefly
 
Google protocol buffers简析
Google protocol buffers简析Google protocol buffers简析
Google protocol buffers简析wavefly
 
ClassLoader简析
ClassLoader简析ClassLoader简析
ClassLoader简析wavefly
 

More from wavefly (6)

The comet technology on Jetty
The comet technology on Jetty The comet technology on Jetty
The comet technology on Jetty
 
Jetty(version 8)核心架构解析
Jetty(version 8)核心架构解析Jetty(version 8)核心架构解析
Jetty(version 8)核心架构解析
 
Head first in xmemcached yanf4j
Head first in xmemcached yanf4jHead first in xmemcached yanf4j
Head first in xmemcached yanf4j
 
Rpc原理与实现
Rpc原理与实现Rpc原理与实现
Rpc原理与实现
 
Google protocol buffers简析
Google protocol buffers简析Google protocol buffers简析
Google protocol buffers简析
 
ClassLoader简析
ClassLoader简析ClassLoader简析
ClassLoader简析
 

Recently uploaded

1.🔥承接黑客破解任务,你的难题我们来解决! 💡无论你是游戏玩家、企业用户还是个人用户,都能在这里找到满意的解决方案。 💪经验丰富的专业团队为您提供全方位...
1.🔥承接黑客破解任务,你的难题我们来解决! 💡无论你是游戏玩家、企业用户还是个人用户,都能在这里找到满意的解决方案。 💪经验丰富的专业团队为您提供全方位...1.🔥承接黑客破解任务,你的难题我们来解决! 💡无论你是游戏玩家、企业用户还是个人用户,都能在这里找到满意的解决方案。 💪经验丰富的专业团队为您提供全方位...
1.🔥承接黑客破解任务,你的难题我们来解决! 💡无论你是游戏玩家、企业用户还是个人用户,都能在这里找到满意的解决方案。 💪经验丰富的专业团队为您提供全方位...黑客 接单【TG/微信qoqoqdqd】
 
正方教务系统的小漏洞被黑客找到啦~他现在正在偷偷溜进去玩呢!(*^__^*)法国大学挂科改成绩 德国大学挂科改成绩 韩国大学挂科改成绩大学成绩修改,找黑客...
正方教务系统的小漏洞被黑客找到啦~他现在正在偷偷溜进去玩呢!(*^__^*)法国大学挂科改成绩 德国大学挂科改成绩 韩国大学挂科改成绩大学成绩修改,找黑客...正方教务系统的小漏洞被黑客找到啦~他现在正在偷偷溜进去玩呢!(*^__^*)法国大学挂科改成绩 德国大学挂科改成绩 韩国大学挂科改成绩大学成绩修改,找黑客...
正方教务系统的小漏洞被黑客找到啦~他现在正在偷偷溜进去玩呢!(*^__^*)法国大学挂科改成绩 德国大学挂科改成绩 韩国大学挂科改成绩大学成绩修改,找黑客...黑客 接单【TG/微信qoqoqdqd】
 
加急代办一个日本秋田县立大学学位记/合格通知书电子版制作/补办国外大学毕业证/CPA证书定制
加急代办一个日本秋田县立大学学位记/合格通知书电子版制作/补办国外大学毕业证/CPA证书定制加急代办一个日本秋田县立大学学位记/合格通知书电子版制作/补办国外大学毕业证/CPA证书定制
加急代办一个日本秋田县立大学学位记/合格通知书电子版制作/补办国外大学毕业证/CPA证书定制paulachevez2
 
【創業簡報練習】當一個人吃飯會想起誰: (A)I-DOLL 陪吃娃娃|科技創業與營運實務
【創業簡報練習】當一個人吃飯會想起誰:(A)I-DOLL 陪吃娃娃|科技創業與營運實務【創業簡報練習】當一個人吃飯會想起誰:(A)I-DOLL 陪吃娃娃|科技創業與營運實務
【創業簡報練習】當一個人吃飯會想起誰: (A)I-DOLL 陪吃娃娃|科技創業與營運實務sardinesaying
 
【国外大学文凭样本】多大毕业证认证Q/微:892798920办多伦多大学毕业证留信留服使馆公公证,多大硕士毕业证,U of T研究生毕业证,文凭,改U o...
【国外大学文凭样本】多大毕业证认证Q/微:892798920办多伦多大学毕业证留信留服使馆公公证,多大硕士毕业证,U of T研究生毕业证,文凭,改U o...【国外大学文凭样本】多大毕业证认证Q/微:892798920办多伦多大学毕业证留信留服使馆公公证,多大硕士毕业证,U of T研究生毕业证,文凭,改U o...
【国外大学文凭样本】多大毕业证认证Q/微:892798920办多伦多大学毕业证留信留服使馆公公证,多大硕士毕业证,U of T研究生毕业证,文凭,改U o...ggbob1
 
保分服务在SAT考试作弊问题上的应对策略和措施是否充分,如何确保服务的可靠性??
保分服务在SAT考试作弊问题上的应对策略和措施是否充分,如何确保服务的可靠性??保分服务在SAT考试作弊问题上的应对策略和措施是否充分,如何确保服务的可靠性??
保分服务在SAT考试作弊问题上的应对策略和措施是否充分,如何确保服务的可靠性??testhelper Sobrenome
 
我曾试图入侵正方教务系统,但我发现它有一些漏洞找黑客入侵电脑,找黑客入侵服务器,找黑客破解密码,怎么找黑客?【微 tytyqqww 信】
我曾试图入侵正方教务系统,但我发现它有一些漏洞找黑客入侵电脑,找黑客入侵服务器,找黑客破解密码,怎么找黑客?【微 tytyqqww 信】我曾试图入侵正方教务系统,但我发现它有一些漏洞找黑客入侵电脑,找黑客入侵服务器,找黑客破解密码,怎么找黑客?【微 tytyqqww 信】
我曾试图入侵正方教务系统,但我发现它有一些漏洞找黑客入侵电脑,找黑客入侵服务器,找黑客破解密码,怎么找黑客?【微 tytyqqww 信】黑客 接单【TG/微信qoqoqdqd】
 
改GPA申请研究生#大学修改成绩修改 #找黑客改分#修改成绩单听说你想改一改在美国大学的成绩?嗯,我明白你的感受。其实,成绩这事儿也不是说改就能改的,你得...
改GPA申请研究生#大学修改成绩修改 #找黑客改分#修改成绩单听说你想改一改在美国大学的成绩?嗯,我明白你的感受。其实,成绩这事儿也不是说改就能改的,你得...改GPA申请研究生#大学修改成绩修改 #找黑客改分#修改成绩单听说你想改一改在美国大学的成绩?嗯,我明白你的感受。其实,成绩这事儿也不是说改就能改的,你得...
改GPA申请研究生#大学修改成绩修改 #找黑客改分#修改成绩单听说你想改一改在美国大学的成绩?嗯,我明白你的感受。其实,成绩这事儿也不是说改就能改的,你得...黑客 接单【TG/微信qoqoqdqd】
 
哪里可以购买日本群马县立县民健康科学大学学位记🏆做个假的文凭可认证吗🏆台湾大学文凭制作🏆托福TOEFL证书定制
哪里可以购买日本群马县立县民健康科学大学学位记🏆做个假的文凭可认证吗🏆台湾大学文凭制作🏆托福TOEFL证书定制哪里可以购买日本群马县立县民健康科学大学学位记🏆做个假的文凭可认证吗🏆台湾大学文凭制作🏆托福TOEFL证书定制
哪里可以购买日本群马县立县民健康科学大学学位记🏆做个假的文凭可认证吗🏆台湾大学文凭制作🏆托福TOEFL证书定制radeybfgkf477
 
听说在加拿大,修改大学成绩单是学霸的日常?求秘籍📚,让我的GPA也能像枫叶一样红得耀眼!#加拿大学霸日常#黑客真的可以改业留学#毕业成绩吗?改了#成绩会被...
听说在加拿大,修改大学成绩单是学霸的日常?求秘籍📚,让我的GPA也能像枫叶一样红得耀眼!#加拿大学霸日常#黑客真的可以改业留学#毕业成绩吗?改了#成绩会被...听说在加拿大,修改大学成绩单是学霸的日常?求秘籍📚,让我的GPA也能像枫叶一样红得耀眼!#加拿大学霸日常#黑客真的可以改业留学#毕业成绩吗?改了#成绩会被...
听说在加拿大,修改大学成绩单是学霸的日常?求秘籍📚,让我的GPA也能像枫叶一样红得耀眼!#加拿大学霸日常#黑客真的可以改业留学#毕业成绩吗?改了#成绩会被...黑客 接单【TG/微信qoqoqdqd】
 
快速定制高仿日本广岛修道大学学位记/入学许可证书PDF修改/意大利大学文凭制作/日语JLPT证书定制
快速定制高仿日本广岛修道大学学位记/入学许可证书PDF修改/意大利大学文凭制作/日语JLPT证书定制快速定制高仿日本广岛修道大学学位记/入学许可证书PDF修改/意大利大学文凭制作/日语JLPT证书定制
快速定制高仿日本广岛修道大学学位记/入学许可证书PDF修改/意大利大学文凭制作/日语JLPT证书定制paulachevez2
 
DIGNITAS INFINITA - 人类尊严 - 教区信仰教义宣言.pptx
DIGNITAS INFINITA - 人类尊严  -  教区信仰教义宣言.pptxDIGNITAS INFINITA - 人类尊严  -  教区信仰教义宣言.pptx
DIGNITAS INFINITA - 人类尊严 - 教区信仰教义宣言.pptxMartin M Flynn
 
30T.ppt【国外大学文凭样本】TWU毕业证认证Q/微:892798920办西三一大学毕业证留信留服使馆公证,TWU硕士毕业证,TWU研究生毕业证,文凭...
30T.ppt【国外大学文凭样本】TWU毕业证认证Q/微:892798920办西三一大学毕业证留信留服使馆公证,TWU硕士毕业证,TWU研究生毕业证,文凭...30T.ppt【国外大学文凭样本】TWU毕业证认证Q/微:892798920办西三一大学毕业证留信留服使馆公证,TWU硕士毕业证,TWU研究生毕业证,文凭...
30T.ppt【国外大学文凭样本】TWU毕业证认证Q/微:892798920办西三一大学毕业证留信留服使馆公证,TWU硕士毕业证,TWU研究生毕业证,文凭...ggbob1
 
为了确保自己的安全和合法权益,我选择购买高品質的假护照、身份证明以及结婚证等证件。这些都是真实有效且具有法律效力的文件【微 tytyqqww 信】
为了确保自己的安全和合法权益,我选择购买高品質的假护照、身份证明以及结婚证等证件。这些都是真实有效且具有法律效力的文件【微 tytyqqww 信】为了确保自己的安全和合法权益,我选择购买高品質的假护照、身份证明以及结婚证等证件。这些都是真实有效且具有法律效力的文件【微 tytyqqww 信】
为了确保自己的安全和合法权益,我选择购买高品質的假护照、身份证明以及结婚证等证件。这些都是真实有效且具有法律效力的文件【微 tytyqqww 信】黑客 接单【TG/微信qoqoqdqd】
 
未毕业在线购买日本长崎县立大学学位记🏆卒业证书外壳什么样子🏆办理比利时大学文凭🏆日语JLPT证书定制
未毕业在线购买日本长崎县立大学学位记🏆卒业证书外壳什么样子🏆办理比利时大学文凭🏆日语JLPT证书定制未毕业在线购买日本长崎县立大学学位记🏆卒业证书外壳什么样子🏆办理比利时大学文凭🏆日语JLPT证书定制
未毕业在线购买日本长崎县立大学学位记🏆卒业证书外壳什么样子🏆办理比利时大学文凭🏆日语JLPT证书定制radeybfgkf477
 
003 DSKP KSSR SEMAKAN 2017 BAHASA CINA TAHUN 3.pdf
003 DSKP KSSR SEMAKAN 2017 BAHASA CINA TAHUN 3.pdf003 DSKP KSSR SEMAKAN 2017 BAHASA CINA TAHUN 3.pdf
003 DSKP KSSR SEMAKAN 2017 BAHASA CINA TAHUN 3.pdfshanshanhui1
 
在中国可以购买日本东京女子大学学位记/做个假的文凭可认证吗/定制马来西亚大学毕业证/CFA证书定制
在中国可以购买日本东京女子大学学位记/做个假的文凭可认证吗/定制马来西亚大学毕业证/CFA证书定制在中国可以购买日本东京女子大学学位记/做个假的文凭可认证吗/定制马来西亚大学毕业证/CFA证书定制
在中国可以购买日本东京女子大学学位记/做个假的文凭可认证吗/定制马来西亚大学毕业证/CFA证书定制paulachevez2
 
1.💥黑客接单,挑战你的想象力! 🚀💡从最炫酷的黑科技到神秘莫测的代码世界,这里都是你想要的技术。无论是破解密码、入侵系统还是开发软件,我们都能帮你实现!...
1.💥黑客接单,挑战你的想象力! 🚀💡从最炫酷的黑科技到神秘莫测的代码世界,这里都是你想要的技术。无论是破解密码、入侵系统还是开发软件,我们都能帮你实现!...1.💥黑客接单,挑战你的想象力! 🚀💡从最炫酷的黑科技到神秘莫测的代码世界,这里都是你想要的技术。无论是破解密码、入侵系统还是开发软件,我们都能帮你实现!...
1.💥黑客接单,挑战你的想象力! 🚀💡从最炫酷的黑科技到神秘莫测的代码世界,这里都是你想要的技术。无论是破解密码、入侵系统还是开发软件,我们都能帮你实现!...黑客 接单【TG/微信qoqoqdqd】
 
未毕业在线购买日本神户国际大学学位记🏆学习成绩单电子版定制🏆仿制西班牙大学毕业证🏆香港中学会考证书定制
未毕业在线购买日本神户国际大学学位记🏆学习成绩单电子版定制🏆仿制西班牙大学毕业证🏆香港中学会考证书定制未毕业在线购买日本神户国际大学学位记🏆学习成绩单电子版定制🏆仿制西班牙大学毕业证🏆香港中学会考证书定制
未毕业在线购买日本神户国际大学学位记🏆学习成绩单电子版定制🏆仿制西班牙大学毕业证🏆香港中学会考证书定制radeybfgkf477
 
未毕业在线购买日本熊本县立大学学位记🏆学习成绩单电子版定制🏆克隆爱尔兰大学文凭🏆CFA证书定制
未毕业在线购买日本熊本县立大学学位记🏆学习成绩单电子版定制🏆克隆爱尔兰大学文凭🏆CFA证书定制未毕业在线购买日本熊本县立大学学位记🏆学习成绩单电子版定制🏆克隆爱尔兰大学文凭🏆CFA证书定制
未毕业在线购买日本熊本县立大学学位记🏆学习成绩单电子版定制🏆克隆爱尔兰大学文凭🏆CFA证书定制gravestomas0
 

Recently uploaded (20)

1.🔥承接黑客破解任务,你的难题我们来解决! 💡无论你是游戏玩家、企业用户还是个人用户,都能在这里找到满意的解决方案。 💪经验丰富的专业团队为您提供全方位...
1.🔥承接黑客破解任务,你的难题我们来解决! 💡无论你是游戏玩家、企业用户还是个人用户,都能在这里找到满意的解决方案。 💪经验丰富的专业团队为您提供全方位...1.🔥承接黑客破解任务,你的难题我们来解决! 💡无论你是游戏玩家、企业用户还是个人用户,都能在这里找到满意的解决方案。 💪经验丰富的专业团队为您提供全方位...
1.🔥承接黑客破解任务,你的难题我们来解决! 💡无论你是游戏玩家、企业用户还是个人用户,都能在这里找到满意的解决方案。 💪经验丰富的专业团队为您提供全方位...
 
正方教务系统的小漏洞被黑客找到啦~他现在正在偷偷溜进去玩呢!(*^__^*)法国大学挂科改成绩 德国大学挂科改成绩 韩国大学挂科改成绩大学成绩修改,找黑客...
正方教务系统的小漏洞被黑客找到啦~他现在正在偷偷溜进去玩呢!(*^__^*)法国大学挂科改成绩 德国大学挂科改成绩 韩国大学挂科改成绩大学成绩修改,找黑客...正方教务系统的小漏洞被黑客找到啦~他现在正在偷偷溜进去玩呢!(*^__^*)法国大学挂科改成绩 德国大学挂科改成绩 韩国大学挂科改成绩大学成绩修改,找黑客...
正方教务系统的小漏洞被黑客找到啦~他现在正在偷偷溜进去玩呢!(*^__^*)法国大学挂科改成绩 德国大学挂科改成绩 韩国大学挂科改成绩大学成绩修改,找黑客...
 
加急代办一个日本秋田县立大学学位记/合格通知书电子版制作/补办国外大学毕业证/CPA证书定制
加急代办一个日本秋田县立大学学位记/合格通知书电子版制作/补办国外大学毕业证/CPA证书定制加急代办一个日本秋田县立大学学位记/合格通知书电子版制作/补办国外大学毕业证/CPA证书定制
加急代办一个日本秋田县立大学学位记/合格通知书电子版制作/补办国外大学毕业证/CPA证书定制
 
【創業簡報練習】當一個人吃飯會想起誰: (A)I-DOLL 陪吃娃娃|科技創業與營運實務
【創業簡報練習】當一個人吃飯會想起誰:(A)I-DOLL 陪吃娃娃|科技創業與營運實務【創業簡報練習】當一個人吃飯會想起誰:(A)I-DOLL 陪吃娃娃|科技創業與營運實務
【創業簡報練習】當一個人吃飯會想起誰: (A)I-DOLL 陪吃娃娃|科技創業與營運實務
 
【国外大学文凭样本】多大毕业证认证Q/微:892798920办多伦多大学毕业证留信留服使馆公公证,多大硕士毕业证,U of T研究生毕业证,文凭,改U o...
【国外大学文凭样本】多大毕业证认证Q/微:892798920办多伦多大学毕业证留信留服使馆公公证,多大硕士毕业证,U of T研究生毕业证,文凭,改U o...【国外大学文凭样本】多大毕业证认证Q/微:892798920办多伦多大学毕业证留信留服使馆公公证,多大硕士毕业证,U of T研究生毕业证,文凭,改U o...
【国外大学文凭样本】多大毕业证认证Q/微:892798920办多伦多大学毕业证留信留服使馆公公证,多大硕士毕业证,U of T研究生毕业证,文凭,改U o...
 
保分服务在SAT考试作弊问题上的应对策略和措施是否充分,如何确保服务的可靠性??
保分服务在SAT考试作弊问题上的应对策略和措施是否充分,如何确保服务的可靠性??保分服务在SAT考试作弊问题上的应对策略和措施是否充分,如何确保服务的可靠性??
保分服务在SAT考试作弊问题上的应对策略和措施是否充分,如何确保服务的可靠性??
 
我曾试图入侵正方教务系统,但我发现它有一些漏洞找黑客入侵电脑,找黑客入侵服务器,找黑客破解密码,怎么找黑客?【微 tytyqqww 信】
我曾试图入侵正方教务系统,但我发现它有一些漏洞找黑客入侵电脑,找黑客入侵服务器,找黑客破解密码,怎么找黑客?【微 tytyqqww 信】我曾试图入侵正方教务系统,但我发现它有一些漏洞找黑客入侵电脑,找黑客入侵服务器,找黑客破解密码,怎么找黑客?【微 tytyqqww 信】
我曾试图入侵正方教务系统,但我发现它有一些漏洞找黑客入侵电脑,找黑客入侵服务器,找黑客破解密码,怎么找黑客?【微 tytyqqww 信】
 
改GPA申请研究生#大学修改成绩修改 #找黑客改分#修改成绩单听说你想改一改在美国大学的成绩?嗯,我明白你的感受。其实,成绩这事儿也不是说改就能改的,你得...
改GPA申请研究生#大学修改成绩修改 #找黑客改分#修改成绩单听说你想改一改在美国大学的成绩?嗯,我明白你的感受。其实,成绩这事儿也不是说改就能改的,你得...改GPA申请研究生#大学修改成绩修改 #找黑客改分#修改成绩单听说你想改一改在美国大学的成绩?嗯,我明白你的感受。其实,成绩这事儿也不是说改就能改的,你得...
改GPA申请研究生#大学修改成绩修改 #找黑客改分#修改成绩单听说你想改一改在美国大学的成绩?嗯,我明白你的感受。其实,成绩这事儿也不是说改就能改的,你得...
 
哪里可以购买日本群马县立县民健康科学大学学位记🏆做个假的文凭可认证吗🏆台湾大学文凭制作🏆托福TOEFL证书定制
哪里可以购买日本群马县立县民健康科学大学学位记🏆做个假的文凭可认证吗🏆台湾大学文凭制作🏆托福TOEFL证书定制哪里可以购买日本群马县立县民健康科学大学学位记🏆做个假的文凭可认证吗🏆台湾大学文凭制作🏆托福TOEFL证书定制
哪里可以购买日本群马县立县民健康科学大学学位记🏆做个假的文凭可认证吗🏆台湾大学文凭制作🏆托福TOEFL证书定制
 
听说在加拿大,修改大学成绩单是学霸的日常?求秘籍📚,让我的GPA也能像枫叶一样红得耀眼!#加拿大学霸日常#黑客真的可以改业留学#毕业成绩吗?改了#成绩会被...
听说在加拿大,修改大学成绩单是学霸的日常?求秘籍📚,让我的GPA也能像枫叶一样红得耀眼!#加拿大学霸日常#黑客真的可以改业留学#毕业成绩吗?改了#成绩会被...听说在加拿大,修改大学成绩单是学霸的日常?求秘籍📚,让我的GPA也能像枫叶一样红得耀眼!#加拿大学霸日常#黑客真的可以改业留学#毕业成绩吗?改了#成绩会被...
听说在加拿大,修改大学成绩单是学霸的日常?求秘籍📚,让我的GPA也能像枫叶一样红得耀眼!#加拿大学霸日常#黑客真的可以改业留学#毕业成绩吗?改了#成绩会被...
 
快速定制高仿日本广岛修道大学学位记/入学许可证书PDF修改/意大利大学文凭制作/日语JLPT证书定制
快速定制高仿日本广岛修道大学学位记/入学许可证书PDF修改/意大利大学文凭制作/日语JLPT证书定制快速定制高仿日本广岛修道大学学位记/入学许可证书PDF修改/意大利大学文凭制作/日语JLPT证书定制
快速定制高仿日本广岛修道大学学位记/入学许可证书PDF修改/意大利大学文凭制作/日语JLPT证书定制
 
DIGNITAS INFINITA - 人类尊严 - 教区信仰教义宣言.pptx
DIGNITAS INFINITA - 人类尊严  -  教区信仰教义宣言.pptxDIGNITAS INFINITA - 人类尊严  -  教区信仰教义宣言.pptx
DIGNITAS INFINITA - 人类尊严 - 教区信仰教义宣言.pptx
 
30T.ppt【国外大学文凭样本】TWU毕业证认证Q/微:892798920办西三一大学毕业证留信留服使馆公证,TWU硕士毕业证,TWU研究生毕业证,文凭...
30T.ppt【国外大学文凭样本】TWU毕业证认证Q/微:892798920办西三一大学毕业证留信留服使馆公证,TWU硕士毕业证,TWU研究生毕业证,文凭...30T.ppt【国外大学文凭样本】TWU毕业证认证Q/微:892798920办西三一大学毕业证留信留服使馆公证,TWU硕士毕业证,TWU研究生毕业证,文凭...
30T.ppt【国外大学文凭样本】TWU毕业证认证Q/微:892798920办西三一大学毕业证留信留服使馆公证,TWU硕士毕业证,TWU研究生毕业证,文凭...
 
为了确保自己的安全和合法权益,我选择购买高品質的假护照、身份证明以及结婚证等证件。这些都是真实有效且具有法律效力的文件【微 tytyqqww 信】
为了确保自己的安全和合法权益,我选择购买高品質的假护照、身份证明以及结婚证等证件。这些都是真实有效且具有法律效力的文件【微 tytyqqww 信】为了确保自己的安全和合法权益,我选择购买高品質的假护照、身份证明以及结婚证等证件。这些都是真实有效且具有法律效力的文件【微 tytyqqww 信】
为了确保自己的安全和合法权益,我选择购买高品質的假护照、身份证明以及结婚证等证件。这些都是真实有效且具有法律效力的文件【微 tytyqqww 信】
 
未毕业在线购买日本长崎县立大学学位记🏆卒业证书外壳什么样子🏆办理比利时大学文凭🏆日语JLPT证书定制
未毕业在线购买日本长崎县立大学学位记🏆卒业证书外壳什么样子🏆办理比利时大学文凭🏆日语JLPT证书定制未毕业在线购买日本长崎县立大学学位记🏆卒业证书外壳什么样子🏆办理比利时大学文凭🏆日语JLPT证书定制
未毕业在线购买日本长崎县立大学学位记🏆卒业证书外壳什么样子🏆办理比利时大学文凭🏆日语JLPT证书定制
 
003 DSKP KSSR SEMAKAN 2017 BAHASA CINA TAHUN 3.pdf
003 DSKP KSSR SEMAKAN 2017 BAHASA CINA TAHUN 3.pdf003 DSKP KSSR SEMAKAN 2017 BAHASA CINA TAHUN 3.pdf
003 DSKP KSSR SEMAKAN 2017 BAHASA CINA TAHUN 3.pdf
 
在中国可以购买日本东京女子大学学位记/做个假的文凭可认证吗/定制马来西亚大学毕业证/CFA证书定制
在中国可以购买日本东京女子大学学位记/做个假的文凭可认证吗/定制马来西亚大学毕业证/CFA证书定制在中国可以购买日本东京女子大学学位记/做个假的文凭可认证吗/定制马来西亚大学毕业证/CFA证书定制
在中国可以购买日本东京女子大学学位记/做个假的文凭可认证吗/定制马来西亚大学毕业证/CFA证书定制
 
1.💥黑客接单,挑战你的想象力! 🚀💡从最炫酷的黑科技到神秘莫测的代码世界,这里都是你想要的技术。无论是破解密码、入侵系统还是开发软件,我们都能帮你实现!...
1.💥黑客接单,挑战你的想象力! 🚀💡从最炫酷的黑科技到神秘莫测的代码世界,这里都是你想要的技术。无论是破解密码、入侵系统还是开发软件,我们都能帮你实现!...1.💥黑客接单,挑战你的想象力! 🚀💡从最炫酷的黑科技到神秘莫测的代码世界,这里都是你想要的技术。无论是破解密码、入侵系统还是开发软件,我们都能帮你实现!...
1.💥黑客接单,挑战你的想象力! 🚀💡从最炫酷的黑科技到神秘莫测的代码世界,这里都是你想要的技术。无论是破解密码、入侵系统还是开发软件,我们都能帮你实现!...
 
未毕业在线购买日本神户国际大学学位记🏆学习成绩单电子版定制🏆仿制西班牙大学毕业证🏆香港中学会考证书定制
未毕业在线购买日本神户国际大学学位记🏆学习成绩单电子版定制🏆仿制西班牙大学毕业证🏆香港中学会考证书定制未毕业在线购买日本神户国际大学学位记🏆学习成绩单电子版定制🏆仿制西班牙大学毕业证🏆香港中学会考证书定制
未毕业在线购买日本神户国际大学学位记🏆学习成绩单电子版定制🏆仿制西班牙大学毕业证🏆香港中学会考证书定制
 
未毕业在线购买日本熊本县立大学学位记🏆学习成绩单电子版定制🏆克隆爱尔兰大学文凭🏆CFA证书定制
未毕业在线购买日本熊本县立大学学位记🏆学习成绩单电子版定制🏆克隆爱尔兰大学文凭🏆CFA证书定制未毕业在线购买日本熊本县立大学学位记🏆学习成绩单电子版定制🏆克隆爱尔兰大学文凭🏆CFA证书定制
未毕业在线购买日本熊本县立大学学位记🏆学习成绩单电子版定制🏆克隆爱尔兰大学文凭🏆CFA证书定制
 

Java并发核心编程

  • 1. Java 并发核心编程 内容涉及: 1、关于 java 并发 2、概念 3、保护共享数据 4、并发集合类 5 线程 6、线程协作及其他 1、关于 java 并发 自从 java 创建以来就已经支持并发的理念,如线程和锁。这篇指南主要是为帮助 java 多线 程开发人员理解并发的核心概念以及如何应用 这些理念。本文的主题是关于具有 java 语言 风格的 Thread、synchronized、volatile,以及 J2SE5 中新增的概念,如锁 (Lock)、原子性 (Atomics)、并发集合类、线程协作摘要、Executors。开发者通过这些基础的接口可以构建高 并发、线程安全的 java 应用程序。 2、概念 本部分描述的 java 并发概念在这篇 DZone Refard 会被通篇使用。 从 JVM 并发看 CPU 内存指令重排序(Memory Reordering):http://kenwublog.com/illustrate-memory-reordering-in-cpu java 内存模型详解: http://kenwublog.com/explain-java-memory-model-in-detail 概念 描述 Java Memory Model 在 JavaSE5(JSR133)中定义的 Java Memory Model(JMM)是为 Java 内存模型 了确保当编写并发代码的时候能够提供 Java 程序员一个可用的 JVM 实现。术语 JMM 的作用类似与一个观察同步读写字段 的 monitor。它按照“happens-before order(先行发生排序) ”的顺序— 可以解释为什么一个线程可以获得其他线程的结果, 这组成了一个 属性同步的程序,使字段具有不变性,以及其他属性。 monitor Java 语言中,每个对象都拥有一个访问代码关键部分并防止其他对 Monitor 象访问这段代码的“monitor” (每个对象都拥有一个对代码关键部 分 提 供 访 问 互 斥 功 能 的 “ monitor ” 。 这 段 关 键 部 分 是 使 用 ) synchronized 对 方 法 或 者 代 码 标 注 实 现 的 。 同 一 时 间 在 同 一 个 monitor 中,只允许一个线程运行代码的任意关键部分。当一个线
  • 2. 程试图获取代码的关键部分时,如果这段代码的 monitor 被其他线 程拥有,那么这个线程会无限期的等待这个 monitor 直到它被其他 线程释放。除了访问互斥之外,monitor 还可以通过 wait 和 notify 来实现协作。 原子字段赋值 除了 doubles 和 longs 之外的类型,给一个这些类型的字段赋值是 Atomic field 一个原子操作。在 JVM 中,doubles 和 longs 的更新是被实现为 2 assignment 个独立的操作, 因此理论上可能会有其他的线程得到一个部分更新 的结果。为了保护共享的 doubles 和 longs,可以使用 volatile 标记 这个字段或者在 synchronized 修饰的代码块中操作字段。 竞争状态 竞争发生在当不少于一个线程对一个共享的资源进行一系列的操 Race condition 作,如果这些线程的操作的顺序不同,会导致多种可能的结果。 数据竞争 数 据 竞 争 主 要 发 生 在 多 个 线 程 访 问 一 个 共 享 的 、 non-final 、 Data race non-volatile、没有合适的 synchronization 限制的字段。Java 内存模 型不会对这种非同步的数据访问提供任何的保证。 在不同的架构和 机器中数据竞争会导致不可预测的行为。 安全发布 在一个对象创建完成之前就发布它的引用时非常危险的。 避免这种 Safe publications 使用这种引用的一种方法就是在创建期间注册一个回调接口。 另外 一种不安全的情况就是在构造子中启动一个线程。在这 2 种情况中, 非完全创建的对象对于其他线程来说都是可见的。 不可变字段 不可变字段在对象创建之后必须明确设定一个值, 否则编译器就会 Final Fields 报出一个错误。 一旦设定值后, 不可变字段的值就不可以再次改变。 将一个对象的引用设定为不可变字段并不能阻止这个对象的改变。 例如,ArrayList 类型的不可变字段不能改变为其他 ArrayList 实例 的引用,但是可以在这个 list 实例中添加或者删除对象。 在创建结尾,对象会遇到”final field freeze”:如果对象被安全的 发布后,即使在没有 synchronization 关键字修饰的情况下,也能保 证所有的线程获取 final 字段在构建过程中设定的值。 final field freezer 不仅对 final 字段有用,而且作用于 final 对象中的可访问属 性。 不可变对象 在语法上 final 字段能够创建不需要 synchronization 修饰的、能够 Immutable objects 被共享读取的线程安全的不可变对象。实现 Immutable Object 需要 保证如下条件: ·对象被安全的发布(在创建过程中 this 引用是无法避免的) ·所有字段被声明为 final ·在创建之后,在对象字段能够被访问的范围中是不允许修改这个 字段的。 ·class 被声明为 final(为了防止 subclass 违反这些规则)
  • 3. 3、保护共享数据 编写线程安全的 java 程序,当修改共享数据的时候要求开发人员使用合适的锁来保护数据。 锁能够建立符合 Java Memory Model 要求的访问顺序,而且确保其他线程知道数据的变化。 注意: 在 Java Memory Model 中,如果没有被 synchronization 修饰,改变数据不需要什么特别的 语法表示。JVM 能够自由地重置指令顺序的特性和对可见性的限制方式很容易让开发人员 感到奇怪。 3.1、Synchronized 3.1、 每个对象实例都拥有一个每次只能让一个线程锁住的 monitor。 synchronized 能够用在一个方 法或者代码块中来锁住这个 monitor。用 synchronized 修饰一个对象,当修改这个对象的一 个字段,synchronized 保证其他线程余下的对这个对象的读操作能够获取修改后的值。需要 注意的是修改同步块之外的数据或者 synchronized 没有修饰当前被修改的对象,那么不能保 证其他线程读到这些最新的数据。synchronized 关键字能够修饰一个对象实例中的函数或者 代码块。在一个非静态方法中 this 关键字表示当前的实例对象。在一个 synchronized 修饰的 静态的方法中,这个方法所在的类使用 Class 作为实例对象。 3.2、Lock 3.2、 Java.util.concurrent.locks 包中有个标准 Lock 接口。ReentrantLock 实现了 Lock 接口,它完全 拥有 synchronized 的特性,同时还提供了新的功能:获取 Lock 的状态、非阻塞获取锁的方 法 tryLock()、可中断 Lock。 下面是使用 ReentrantLock 的详细示例: public class Counter{ private final Lock lock = new ReentrantLock(); private int value; public int increment() { lock.lock(); try { return ++value; finally finally{ }finally lock.unlock(); } } }
  • 4. 3.3、ReadWriteLock 3.3、 Java.util.concurrent.locks 包中还有个 ReadWriteLock 接口(实现类是 ReentrantWriteReadLock) ,它定义一对锁:读锁和写锁,特征是能够被并发的读取但每次只 能有一个写操作。使用 ReentrantReadWriteLock 并发读取特性的详细示例: public class ReadWrite { private final ReadWriteLock lock = new ReentrantReadWriteLock(); private int value; public void increment(){ lock.writeLock().lock(); try try{ value++; finally finally{ }finally lock.writeLock().unlock(); } } public int current(){ lock.readLock().lock(); try try{ return value; finally finally{ }finally lock.readLock().unlock(); } } } 3.4、volatile 3.4、 volatile 原理与技巧: http://kenwublog.com/the-theory-of-volatile volatile 修饰符用来标注一个字段,表明任何对这个字段的修改都必须能被其他随后访问的 线程获取到,这个修饰符和同步无关。因此,volatile 修饰的数据的可见性和 synchronization 类似,但是这个它只作用于对字段的读或写操作。在 JavaSE5 之前,因为 JVM 的架构和实 现的原因,不同 JVM 的 volatile 效果是不同的而且也是不可信的。下面是 Java 内存模型明 确地定义 volatile 的行为: public class Processor implements Runnable { private volatile boolean stop; public void stopProcessing(){ stop = true true; } public void run() { while (!stop) {
  • 5. //do processing } } } 注意:使用 volatile 修饰一个数组并不能让这个数组的每个元素拥有 volatile 特性, 这种声明 只是让这个数组的 reference 具有 volatile 属性。数组被声明为 AtomicIntegerArray 类型,则 能够拥有类似 volatile 的特性。 3.5、原子类 3.5、原子类 使用 volatile 的一个缺点是它能够保证数据的可见性,却不能在一个原子操作中对 volatile 修饰的字段同时进行校验和更新操作。 java.util.concurrent.atomic 包中有一系列支持在单个非 锁定(lock)的变量上进行原子操作的类,类似于 volatile。示例: public class Counter{ private AtomicInteger value = new AtomicInteger(); private int value; public int increment() { return value.incrementAndGet(); } } incrementAndGet 方法是原子类的复合操作的一个示例。booleans, integers, longs, object references, integers 数组, longs 数组, object references 数组 都有相应的原子类。 3.6、ThreadLocal 3.6、 通过 ThreadLocal 能数据保存在一个线程中,而且不需要 lock 同步。理论上 ThreadLocal 可 以让一个变量在每个线程都有一个副本。 ThreadLocal 常用来屏蔽线程的私有变量, “并 例如 发事务”或者其他的资源。而且,它还被用来维护每个线程的计数器,统计,或者 ID 生成 器。 public class TransactionManager { private static final ThreadLocal<Transaction> currentTransaction = new ThreadLocal<Transaction>() { @Override protected Transaction initialValue() { return new NullTransaction(); } }; public Transaction currentTransaction() { Transaction current = currentTransaction.get(); if if(current.isNull()) { current = new TransactionImpl();
  • 6. currentTransaction.put(current); } return current; } } 4、Concurrent Collections Concurrent Collections(并发集合类) 保护共享数据的一个关键技术是在存储数据的类中封装同步机制。 所有对数据的使用都要经 过同步机制的确认使这个技术能够避免数据的不当访问。在 java.util.concurrent 包中有很多 为并发使用情况下设计的数据结构。通常,使用这些数据结构比使用同步包装器装饰的非同 步的集合的效率更高。 4.1、Concurrent lists and sets 4.1、 在 Table2 中列出了 java.util.concurrent 包中拥有的 3 个并发的 List 和 Set 实现类。 类 描述 CopyOnWriteArraySet CopyOnWriteArraySet 在语意上提供写时复制(copy-on-werite)的特 性,对这个集合的每次修改都需要对当前数据结构新建一个副本, 因此写操作发费很大。在迭代器创建的时候,会对当前数据数据结 构创建一个快照用于迭代。 CopyOnWriteArrayList CopyOnWriteArrayList 和 CopyOnWriteArraySet 类似,也是基于 copy-on-write 语义实现了 List 接口 ConcurrentSkipListSet ConcurrentSkipListSet(在 JavaSE 6 新增的)提供的功能类似于 TreeSet,能够并发的访问有序的 set。因为 ConcurrentSkipListSet 是 基于“跳跃列表(skip list) ”实现的,只要多个线程没有同时修改 集合的同一个部分,那么在正常读、写集合的操作中不会出现竞争 现象。 skip list: http://blog.csdn.net/yuanyufei/archive/2007/02/14/1509937.aspx http://zh.wikipedia.org/zh-cn/%E8%B7%B3%E8%B7%83%E5%88%97%E8%A1%A8 4.2、Concurrent maps 4.2、 Java.util.concurrent 包中有个继承 Map 接口的 ConcurrentMap 的接口,ConcurrentMap 提供了 一些新的方法(表 3) 。所有的这些方法在一个原子操作中各自提供了一套操作步骤。如果 将每套步骤在放在 map 之外单独实现,在非原子操作的多线程访问的情况下会导致资源竞 争。 表 3:ConcurrentMap 的方法:
  • 7. 方法 描述 putIfAbsent(K key, V value) : V 如果 key 在 map 中不存在,则把 key-value 键值对放入 map 中,否则不执行任何操作。返回值为原来的 value,如果 key 不存在 map 中则返回 null remove(Object key, Object 如果 map 中有这个 key 及相应的 value,那么移除这对数据, value) : boolean 否则不执行任何操作 replace (K key, V value) : V 如果 map 中有这个 key,那么用新的 value 替换原来的 value, 否则不执行任何操作 replace (K key, V oldValue, V 如果 map 中有这对 key-oldValue 数据,那么用 newValue 替 newValue) : boolean 换原来的 oldValue,否则不执行任何操作 在表 4 中列出的是 ConcurrentMap 的 2 个实现类 方法 描述 ConcurrentHashMap ConcurrentHashMap 提供了 2 种级别的内部哈希方法。第一 种级别是选择一个内部的 Segment,第二种是在选定的 Segment 中将数据哈希到 buckets 中。第一种方法通过并行 地在不同的 Segment 上进行读写操作来实现并发。 (ConcurrentHashMap 是引入了 Segment,每个 Segment 又是 一个 hash 表,ConcurrentHashMap 相当于是两级 Hash 表, 然后锁是在 Segment 一级进行的,提高了并发性。 http://mooncui.javaeye.com/blog/380884 http://www.javaeye.com/topic/344876 ) ConcurrentSkipListMap ConcurrentSkipListMap(JavaSE 6 新增的类)功能类似 TreeMap,是能够被并发访问的排序 map。尽管能够被多线 程正常的读写---只要这些线程没有同时修改 map 的同一个 部分,ConcurrentSkipListMap 的性能指标和 TreeMap 差不 多。 4.3、Queues 4.3、 Queues 类似于沟通“生产者”和“消费者”的管道。组件从管道的一端放入,然后从另一 端取出: “先进先出”(FIFO)的顺序。Queue 接口在 JavaSE5 新添加到 java.util 中的,能够被 用于单线程访问的场景中,主要适用于多个生产者、一个或多个消费者的情景,所有的读写 操作都是基于同一个队列。 java.util.concurrent 包中的 BlockingQueue 接口是 Queue 的子接口,而且还添加了新的特性处 理如下场景:队列满(此时刚好有一个生产者要加入一个新的组件) 、队列空(此时刚好有 一个消费者读取或者删除一个组件) BlockingQueue 提供如下方案解决这些情况: 。 一直阻塞 等待直到其他线程修改队列的数据状态;阻塞一段时间之后返回,如果在这段时间内有其他 线程修改队列数据,那么也会返回。 表 5:Queue 和 BlockingQueue 的方法: 方法 策略 插入 移除 核查 Queue 抛出异常 add remove element
  • 8. 返回特定的值 offer poll peek Blocking Queue 一直阻塞 put take n/a 超时阻塞 offer poll n/a 在 JDK 中提供了一些 Queue 的实现,在表 6 中是这些实现类的关系列表。 方法 描述 PriorityQueue PriorityQueue 是唯一一个非线程安全的队列实现类,用于单 线程存放数据并且将数据排序。 CurrentLinkedQueue 一个无界的、基于链接列表的、唯一一个线程安全的队列实 现类,不支持 BlockingQueue。 ArrayBlockingQueue 一个有界的、基于数组的阻塞队列。 LinkedBlockingQueue 一个有界的、基于链接列表的阻塞队列。有可能是最常用的 队列实现。 PriorityBlockingQueue 一个无界的、 基于堆的阻塞队列。 队列根据设置的 Comparator (比较器)来确定组件读取、移除的顺序(不是队列默认的 FIFO 顺序) DelayQueue 一个无界的、延迟元素(每个延迟元素都会有相应的延迟时 间值)的阻塞队列实现。只有在延时期过了之后,元素才能 被移除,而且最先被移除的是延时最先到期的元素。 SynchronousQueue 一种 0 容量的队列实现,生产者添加元素之后必须等待消费 者移除后才可以返回,反之依然。如果生产者和消费者 2 个 线程同时访问,那么参数直接从生产者传递到消费者。经常 用于线程之间的数据传输。 4.4、Deque 4.4、 在 JavaSE6 中新增加了两端都可以添加和删除的队列-Deque (发音"deck",not "dick"). Deques 不仅可以从一端添加元素,从另一端移除,而且两端都可以添加和删除元素。如 同 BlockingQueue,BlockingDeque 接口也为阻塞等待和超时等待的特殊情况提供了解决方法。 因为 Deque 继承 Queue、 BlockingDeque 继承 BlockingQueue,下表中的方法都是可以使用的: 接口 头或尾 策略 插入 移除 核查 Queue Head 抛出异常 addFirst removeFirst getFirst 返回特定的值 offerFirst pollFirst peekFirst Tail 抛出异常 addLast removeLast getLast 返回特定的值 offerLast pollLast peekLast Blockin Head 一直阻塞 putFirst takeFirst n/a gQueue 超时阻塞 offerFirst pollFirst n/a Tail 一直阻塞 putLast takeLast n/a 超时阻塞 offerLast pollLast n/a Deque 的一个特殊应用场景是只在一个端口进行添加、 删除、检查操作--堆栈(first-in-last-out 顺序)。Deque 接口提供了 stack 相同的方法:push(), pop()和 peek(),这方法和 addFirst(), removeFirst(), peekFirst()一一对应,可以把 Deque 的任何一个实现类当做堆栈使用。表 6 中
  • 9. 是 JDK 中 Deque 和 BlockingDeque 的实现。注意 Deque 继承 Queue,BlockingDeque 继承自 BlockingQueue。 表 8:Deques 类 描述 LinkedList 这个经常被用到的类在 JavaSE6 中有了新的 改进-实现了 Deque 接口。在 LinkedList 中, 可以使用标准的 Deque 方法来添加或者删除 list 两端的元素。LinkedList 还可以被当做一 个非同步的堆栈,用来替代同步的 Stack 类 ArrayDeque 一个非同步的、支持无限队列长度(根据需 要动态扩展队列的长度)的 Deque 实现类 LinkedBlockingDeque LinkeBlockingDeque 是 Deque 实现中唯一支 持并发的、基于链接列表、队列长度可选的 类。 5、线程 在 Java 中,java.lang.Thread 类是用来代表一个应用或者 JVM 线程。代码是在某个线程类的 上下文环境中执行的(使用 Thread.currentThread()来获取当前运行的线程) 。 5.1、线程通讯 5.1、线程通讯 线程之间最简单的通讯方式是一个线程直接调用另一个线程对象的方法。 9 中列出的是线 表 程之间可以直接交互的方法。 表 9:线程协作方法 线程方法 描述 start 启动一个线程实例,并且执行它的 run() 方法。 join 一直阻塞直到其他线程退出 interrupt 中断其他线程。线程如果在一个方法中被阻塞,会对 interrupt 操作做出回应,并在这个方法执行的线程中抛出 InterruptedException 异常;否则线程的中断状态被设定。 stop, suspend, resume, destroy 这些方法都被废弃, 不应该再使用了。因为线程处理过程中 状态问题会导致危险的操作。相反,应该使用 interrupt() 或 者 volatile 标示来告诉一个线程应该做什么。 5.2、"未捕获异常"处理器 5.2、 未捕获异常" 线程能够指定一个 UncaughtExceptionHandler 来接收任何一个导致线程非正常突然终止的未 捕获异常的通知。
  • 10. Thread t = new Thread(runnable); new t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { // TODO get Logger and log uncaught exception } }); t.start(); 5.3、死锁 5.3、死锁 当存在多个线程(最少 2 个)等待对方占有的资源,就会形成资源循环依赖和线程等待, 产 生死锁。最常见的导致死锁的资源是对象 monitor,同时其他阻塞操作(例如 wait/notify)也 能导致死锁。 很多新的 JVM 能够检测 Monitor 死锁,并且可以将线程 dump 中由信号(中断信号) 、jstack 或者其他线程 dump 工具生成的死锁原因显示打印出来。 除了死锁,线程之间还会出现饥饿(starvation)和活锁(livelock). Starvation 是因为一个线程 长时间占有一个锁导致其他的线程一直处于等待状态无法进行下一步操作。 Livelock 是因为 线程发费大量的时间来协调资源的访问或者检测避免死锁导致没有一个线程真正的干活。 6、线程协作 6.1、wait/notify 6.1、 wait/notify 关键字适用于一个线程通知另一个线程所需的条件状态已就绪,最常用于线程在 循环中休眠直到获取特定条件的场景. 例如,一个线程一直等待直到队列中有一个组件能够 处理;当组件添加到队列时,另一个线程能够通知这个等待的线程。 wait 和 notify 的经典用法是: public class Latch { private final Object lock = new Object(); private volatile boolean flag = false false; public void waitTillChange(){ synchronized (lock) { while while(!flag){ try { lock.wait();
  • 11. } catch (InterruptedException e) { } } } } public void change(){ synchronized (lock) { flag = true true; lock.notifyAll(); } } } 在代码中需要注意的重要地方是: � wait、notify、notifyAll 必须在 synchronized 修饰的代码块中执行,否则会在运行的时候 抛出 IllegalMonitorStateException 异常 � 在循环语句 wait 的时候一定要设定循环的条件--这样能够避免 wait 开始之前,线程所 需的条件已经被其他线程提供了却依然开始此线程 wait 导致的时间消耗。同时,这种 办法还能够保证你的代码不被虚假的信息唤醒。 � 总是要保证在调用 notify 和 notifyAll 之前,能够提供符合线程退出等待的条件。否则 会出现即使线程接收到通知信息,却不能退出循环等待的情况。 6.2、Condition 6.2、 在 JavaSE5 中新添加了 java.util.concurrent.locks.Condition 接口。Condition 不仅在 API 中实 现了 wait/notify 语义,而且提供了几个新的特性,例如:为每个 Lock 创建多重 Condition、 可中断的等待、访问统计信息等。Condition 是通过 Lock 示例产生的,示例:
  • 12. public class LatchCondition { private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private volatile boolean flag = false false; public void waitTillChange(){ lock.lock(); try try{ while while(!flag){ try { condition.await(); } catch (InterruptedException e) { } } finally finally{ }finally lock.unlock(); } } public void change(){ lock.lock(); try try{ flag = true true; condition.notifyAll(); finally finally{ }finally lock.unlock(); } } } 6.3、Coordination classes 6.3、 java.util.concurrent 包中有几个类适用于常见的多线程通讯。 这几个协作类适用范围几乎涵盖 了使用 wait/notify 和 Condition 最常见的场景,而且更安全、更易于使用。 CyclicBarrier 在 CyclicBarrier 初始化的时候指定参与者的数量。参与者调用 awart()方法进入阻塞状态直 到参与者的个数达到指定数量, 此时最后一个到达的线程执行预定的屏障任务, 然后释放所 有的线程。屏障可以被重复的重置状态。常用于协调分组的线程的启动和停止。 CountDownLatch 需要指定一个计数才能初始化 CountDownLatch。线程调用 await()方法进入等待状态知道计
  • 13. 数变为 0。其他的线程(或者同一个线程)调用 countDown()来减少计数。如果计数变为 0 后是无法被重置的。常用于当确定数目的操作完成后,触发数量不定的线程。 Semaphore Semaphore 维护一个“许可”集,能够使用 acquire()方法检测这个“许可”集,在“许可” 可用之前 Semaphore 会阻塞每个 acquire 访问。线程能够调用 release()来返回一个许可。当 Semaphore 只有一个“许可”的时候,可当做一个互斥锁来使用。 Exchanger 线程在 Exchanger 的 exchange()方法上进行交互、原子操作的方式交换数据。功能类似于数 据可以双向传递的 SynchronousQueue 加强版。 7、任务执行 很多 java 并发程序需要一个线程池来执行队列中的任务。在 java.util.concurrent 包中为这种 类型的任务管理提供了一种可靠的基本方法。 7.1、ExecutorService 7.1、 Executor 和易扩展的 ExecutorService 接口规定了用于执行任务的组件的标准。这些接口的使 用者可以通过一个标准的接口使用各种具有不同行为的实现类。 最通用的 Executor 接口只能访问这种类型的可执行(Runnable)任务 : void execute(Runnable command) Executor 子接口 ExecutorService 新加了方法,能够执行:Runnable 任务、Callable 任务以及 任务集合。 Future<?> submit(Runnable task) Future<T> submit(Callable<T> task) Future<T> submit(Runnable task, T result) List<Future<T>> invokeAll (Collection<? extends Callable<T>> tasks) List<Future<T>> invokeAll (Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) T invokeAny(Collection<? extends Callable<T>> tasks) T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) 7.2、Callable and Future 7.2、 Callable 类似于 Runnable,而且能够返回值、抛出异常: � V call() throws Exception; 在一个任务执行框架中提交一个 Callable 任务, 然后返回一个 Future 结果是很常见的。 Future 表示在将来的某个时刻能够获取到结果。 Future 提供能够获取结果或者阻塞直到结果可用的
  • 14. 方法。任务运行之前或正在运行的时候,可以通过 Future 中的方法取消。 如果只是需要一个 Runnable 特性的 Future(例如在 Executor 执行) ,可用使用 FutureTask。 FutureTask 实现了 Future 和 Runnable 接口,可用提交一个 Runnable 类型任务,然后在调用 部分使用这个 Future 类型的任务。 7.3、实现 ExecutorService 7.3、实现 ExecutorService 最主要的实现类是 ThreadPoolExecutor。这个实现类提供了大量的可配置特 性: � 线程池--设定常用线程数量(启动前可选参数)和最大可用线程数量。 � 线程工厂--通过自定义的线程工厂生成线程,例如生成自定义线程名的线程。 � 工作队列--指定队列的实现类,实现类必须是阻塞的、可以是无界的或有界的。 � 被拒绝的任务--当队列已经满了或者是执行者不可用,需要为这些情况指定解决策略。 � 生命周期中的钩子--重写扩展在任务运行之前或之后的生命周期中的关键点 � 关闭--停止已接受的任务,等待正在运行的任务完成后,关闭 ThreadPoolExecutor。 ScheduledThreadPoolExecutor 是 ThreadPoolExecutor 的一个子类,能够按照定时的方式完成 任务(而不是 FIFO 方式) 。在 java.util.Timer 不是足够完善的情况下, ScheduleThreadPoolExecutor 具有强大的可适用性。 Executors 类有很多静态方法(表 10)用于创建适用于各种常见情况的预先包装的 ExecutorService 和 ScheduleExecutorService 实例 表 10 方法 描述 newSingleThreadExecutor 创建只有一个线程的 ExecutorService newFixedThreadPool 返回拥有固定数量线程的 ExecutorService newCachedThreadPool 返回一个线程数量可变的 ExecutorService newSingleThreadScheduledExecutor 返回只有一个线程的 ScheduledExecutorService newScheduledThreadPool 创建拥有一组核心线程的 ScheduledExecutorService 下面的例子是创建一个固定线程池,然后提交一个长期运行的任务:
  • 15. int processors = Runtime.getRuntime().availableProcessors(); ExecutorService executor = Executors.newFixedThreadPool(processors); Future<Integer> futureResult = new executor.submit(new Callable<Integer>() { public Integer call() { //long time computation that returns an Integer return null null; } }); Integer result = futureResult.get(); 在这个示例中提交任务到 executor 之后,代码没有阻塞而是立即返回。在代码的最后一行调 用 get()方法会阻塞直到有结果返回。 ExecutorService 几乎涵盖了所有应该创建线程对象或线程池的情景。 在代码中需要直接创建 一个线程的时候,可以考虑通过 Executor 工厂创建的 ExecutorService 能否实现相同的目标; 这样做经常更简单、更灵活。 7.4、CompletionService 除了常见的线程池和输入队列模式,还有一种常见的情况:为后面的处理,每个任务生成的 结果必须积累下来。CompletionService 接口允许提交 Callable 和 Runnable 任务,而且还可 以从任务队列中获取这些结果: (绿色部分和英文版不一样,已和作者确认,英文版将 take() 和 poll()方法混淆了) � Future<V> take () -- 如果结果存在则获取,否则直接返回 � Future<V> poll () -- 阻塞直到结果可用 � Future<V> poll (long timeout, TimeUnit unit) -- 阻塞直到 timeout 时间结束 ExecutorCompletionService 是 CompletionService 的标准实现类。 ExecutorCompletionService 在 的构成函数中需要一个 Executor,ExecutorCompletionService 提供输入队列和线程池。 8、Hot Tip Hot 热门信息:当设置线程池大小的时候, 最好是基于当前应用所运行的机器拥有的逻辑处 理器的数量。在 java 中,可用使用 Runtime.getRuntime().availableProcessors()获取这个值。 在 JVM 的生命周期中,可用处理器的数目是可变的。
  • 16. 9、关于作者 Alex Miller 是 Terracotta Inc 公司 Java 集群开源产品的技术负责人, 曾在 BEA System 和 MetaMatrix 工作,是 MetaMatrix 的首席架构师。他对 Java、并发、分布式系统、查询语言 和软件设计感兴趣。他的 tweeter:@puredanger,blog:http://tect.puredanger.com,很喜欢在 用户组会议中发言。在 St. Louis,Alex 是 Lambda Lounge 小组的创建人,Lambda Lounge 用户组是为了学习、动态语言、Strange Loop 开发会议而创建的。 10 10、翻译后记 开始阅读英文版的时候,并没有觉得文章中有什么晦涩的地方。但是在翻译之后,才发 现将文中的意思清楚地表达出来也是个脑力活, 有时一句话能够懂得意思, 却是很难用汉语 表达出来: “只可意会,不可言传”--这也能解释我当年高中作文为啥每次只能拿 40 分(总 分 60)。在禅宗,师傅教弟子佛理,多靠弟子自身的明悟,故有当头棒喝、醍醐灌顶之说。 做翻译却不能这样,总不能让读者对着满篇的鸟文去琢磨明悟吧,须得直译、意译并用, 梳 理文字。 翻译也是一个学习的过程。阅读本文的时候会无意忽略自己以为不重要的词句, 待到真 正翻译的时候,才发现自己一知半解、一窍不通,就只好 Google 之,翻译完成后,也学了 些知识,可谓是一箭双雕。 个人精力所限,翻译中难免有不对的地方,望大家予以指正。 联系方式:MSN/E-Mail:nathanlhb@hotmail.com Blog:http://blog.csdn.net/liu251