Oracle官方并发教程

前端之家收集整理的这篇文章主要介绍了Oracle官方并发教程前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

原文

进程和线程

进程

进程具有一个独立的执行环境。通常情况下,进程拥有一个完整的、私有的基本运行资源集合。特别地,每个进程都有自己的内存空间。

了便于进程之间的通信,大多数操作系统都支持进程间通信(IPC),如pipes 和sockets。

IPC不仅支持同一系统上的通信,也支持不同的系统。Java虚拟机的大多数实现是单进程的。

Java应用可以使用的ProcessBuilder对象创建额外的进程,多进程应用超出了本课的范围。

线程

线程是在进程中存在的 — 每个进程最少有一个线程。线程共享进程的资源,包括内存和打开的文件。这样提高了效率,但潜在的问题就是线程间的通信。

不可变对象(只能读不能写)

一个对象如果在创建后不能被修改,那么就称为不可变对象。在并发编程中,一种被普遍认可的原则就是:尽可能的使用不可变对象来创建简单、可靠的代码
在并发编程中,不可变对象特别有用。由于创建后不能被修改,所以不会出现由于线程干扰产生的错误或是内存一致性错误

但是程序员们通常并不热衷于使用不可变对象,因为他们担心每次创建新对象的开销。实际上这种开销常常被过分高估,而且使用不可变对象所带来的一些效率提升也抵消了这种开销。例如:使用不可变对象降低了垃圾回收所产生的额外开销,也减少了用来确保使用可变对象不出现并发错误的一些额外代码

定义不可变对象的策略

  1. 不要提供setter方法。(包括修改字段的方法修改字段引用对象的方法
  2. 将类的所有字段定义为final、private的。
  3. 不允许子类重写方法。简单的办法是将类声明为final,更好的方法是将构造函数声明为私有的,通过工厂方法创建对象。
  4. 如果类的字段是对可变对象的引用,不允许修改被引用对象。
  5. 不提供修改可变对象的方法
  6. 不共享可变对象的引用。当一个引用被当做参数传递给构造函数,而这个引用指向的是一个外部的可变对象时,一定不要保存这个引用。如果必须要保存,那么创建可变对象的拷贝,然后保存拷贝对象的引用。同样如果需要返回内部的可变对象时,不要返回可变对象本身,而是返回其拷贝。

Fork/Joint

fork/join框架是ExecutorService接口的一种具体实现,目的是为了帮助你更好地利用多处理器带来的好处。它是为那些能够被递归地拆解成子任务的工作类型量身设计的。其目的在于能够使用所有可用的运算能力来提升你的应用的性能。类似于ExecutorService接口的其他实现,fork/join框架会将任务分发给线程池中的工作线程。fork/join框架的独特之处在于它使用工作窃取(work-stealing)算法。完成自己的工作而处于空闲的工作线程能够从其他仍然处于忙碌(busy)状态的工作线程处窃取等待执行的任务。 fork/join框架的核心是ForkJoinPool类,它是对AbstractExecutorService类的扩展。ForkJoinPool实现了工作偷取算法,并可以执行ForkJoinTask任务。

基本使用方法

使用fork/join框架的第一步是编写执行一部分工作的代码。你的代码结构看起来应该与下面所示的伪代码类似:

if (当前这个任务工作量足够小)
    直接完成这个任务
else
    将这个任务或这部分工作分解成两个部分
    分别触发(invoke)这两个子任务的执行,并等待结果

你需要将这段代码包裹在一个ForkJoinTask的子类中。不过,通常情况下会使用一种更为具体的的类型,或者是RecursiveTask(会返回一个结果),或者是RecursiveAction。 当你的ForkJoinTask子类准备好了,创建一个代表所有需要完成工作的对象,然后将其作为参数传递给一个ForkJoinPool实例的invoke()方法即可。

除了能够使用fork/join框架来实现能够在多处理系统中被并行执行的定制化算法(如前文中的ForkBlur.java例子),在Java SE中一些比较常用的功能点也已经使用fork/join框架来实现了。在多处理器系统中,对大数组的并行排序会比串行排序更快。

在Java SE 8中,java.util.Arrays类的一系列parallelSort()方法就使用了fork/join来实现。这些方法sort()系列方法很类似,但是通过使用fork/join框架,借助了并发来完成相关工作。

猜你在找的Oracle相关文章