并发的JVM:Java和Scala的并发性基础知识

在处理器的速度持续快速发展几十年来在世纪之交的结束。自那时以来,处理器制造商提高芯片的性能更加芯通过提高时钟速度比。多核心系统现在为从手机到企业服务器所有的规范,而且这种趋势很可能会继续加快。越来越多,开发商必须解决多核在他们的应用程序代码来满足性能要求。

在本系列文章中,您将看到一些新的方法来并行编程的JavaScala语言,包括Java是如何将思想已探索Scala和其他基于JVM的语言。这第一部分会给你一个理解的并行编程更广阔的画面在JVM中引入一些为Java 7Scala当前最先进的技术背景。您将学习如何使用JavaExecutorServiceforkjoinpool类来简化并行编程。你也会得到一些扩展并行编程选项在平原Java有什么基本Scala介绍。一路上,你会看到不同的途径影响并行程序的性能。后续的文章将盖在Java 8并发的改善,随着扩展包括啊卡可扩展的JavaScala编程工具包。

Java并发支持

并发支持从平台的初期是一个Java线程和同步功能,以使其竞争优势廉洁执行语言。基于JavaScalaJVM上运行,直接访问所有的Java运行时(包括所有的并发支持)。所以在寻找到Scala的特点,我就开始了一个快速回顾一下Java语言已经供应。

基本的Java线程

线程是易于创建和使用Java编程。他们所代表的java.lang.thread类,和编码由一个线程执行的是一种形式java.lang.runnable实例。你如果到成千上万的应用程序需要创建大量线程。当多个内核是可用的,JVM使用它们来执行多个线程同时;在核心数量过多线程共享的核心。

5Java并发流域

Java从一开始就支持线程和同步。但小于螺纹之间的主要变化引起Java语言,Java 5更新共享数据的防弹初始规格(JSR-133)。Java语言规范的 Java 5纠正和形式化的操作同步的挥发性的。该规范还规定了如何不可变对象和多线程的工作。(基本上,不可变对象的引用都是线程安全的规定不允许越狱而构造函数被执行。)以前,线程通常需要使用阻塞之间的相互作用同步的运营的变化,使非通过使用阻塞线程之间的协调挥发性的。作为一个结果,新的并发集合类中增加了Java 5,支持非阻塞操作-在早期的阻塞线程安全的唯一方法的一个主要的改进。

协调线程的行为变得混乱。一种并发症发生因为Java编译器和JVM可以自由的在你的代码重新排序操作,只要一切保持一致,从程序的角度来看。例如:如果两个加法运算,使用不同的变量,编译器和JVM可以以相反的顺序执行你指定的操作,提供程序不使用和操作完成之前。这种灵活性来重新排序操作有助于提高Java性能,但一致性保证仅适用于单线程。硬件也可以创建线程的问题。现代系统使用多层次的快取记忆体,和高速缓存通常是没有看到相同的系统中的所有核心。当一个核心修改内存中的值,改变可能不是立即可见的其他核心。

由于这些问题,当一个线程的数据由另一个线程修改工作,你必须明确地控制多线程交互。Java使用特殊的操作提供这种控制,在看到不同线程的数据视图建立序。基本操作的线程的使用同步的关键词来访问一个对象。当一个线程同步对象,线程获取锁的对象的独家访问。如果另一个线程已持有锁,想要获得它必须等待的线程,或,直到锁被释放。当线程继续执行内部同步的块的代码,Java可以保证线程看见的一切都被其他线程,先前持有的同一锁-但这些线程释放锁到他们离开自己的时间只写数据写同步的块。这保证了既适用于由编译器和JVM执行操作重新排序和硬件的内存缓存。一个内部同步的块,然后,是一个稳定的岛屿在你的代码中的线程可以轮流执行,相互作用,和共享信息的安全。

使用的挥发性的在可变的关键字提供了一个稍微弱形式的安全线程间的相互作用。的同步的关键词保证当你获得锁,你看到其他线程的商店,和其他线程后你会看到你的店获得锁。的挥发性的关键词违反这一担保分成两个单独的块。如果一个线程写入挥发性的变量,所有之前,首先得写点。如果一个线程读取变量,它认为不仅值写入该变量也是所有其他值的写作思路,写。所以阅读挥发性的变量提供了保证相同的记忆进入A同步的块,和写作挥发性的变量给出了保证相同的记忆离开A同步的块。但有一个很大的不同:阅读或写作挥发性的变量没有块。

抽象Java并发

同步是有用的,和多线程应用中只使用基本的Java开发同步的块。但协调线程可以是混乱的,特别是当你在处理多线程和多锁。确保线程安全的方式相互作用仅在你避免潜在的死锁(两个或多个线程在等待对方才可以继续执行释放锁)变得困难。不直接与抽象,支持并发线程和锁处理给开发者更好的方法来处理常见的使用情况。

java.util.concurrent层次结构包括集合的变化,支持并发访问,原子操作的封装类,和同步原语。许多这类被设计为支持非阻塞通道,从而避免了问题的僵局,使更高效的线程。这类更容易界定和规范之间的相互作用的线,但他们仍然受到一些基本的线程模型的复杂性。

在一对抽象java.util.concurrent包支持一个更解耦的方法来处理并发的未来的<t >接口,和执行器ExecutorService接口这些相关的接口又是许多ScalaJava并发阿卡扩展支持的基础,所以值得看的接口及其实现的更多细节。

未来的<t >一种价值类型的人T,与扭曲的价值通常是不可用,直到一段时间后期货创建。价值是一个异步操作可能同时执行的结果。线程接收期货可以调用方法:

<!--[if !supportLists]-->·         <!--[endif]-->如果值是可用的

<!--[if !supportLists]-->·         <!--[endif]-->等待成为可用的值

<!--[if !supportLists]-->·         <!--[endif]-->检索该值可用时

<!--[if !supportLists]-->·         <!--[endif]-->如果该值是不再需要取消操作

具体实现方法期货的结构,以支持不同的处理异步操作方式。

执行器在执行任务的一个抽象的东西。这东西将最终被一个线程,但具体如何执行的线程句柄是隐藏的接口。执行器是对自己有用的限制,与ExecutorService接口提供扩展的方法来管理终端和生产期货的任务的结果。所有标准的实现执行器同时实施ExecutorService因此,在实践中,你可以忽略的根接口。OA办公系统

线程是比较重量级的资源,是明智的,而不是分配和丢弃他们的重用。ExecutorService简化的线程之间共享的工作,同时也使线程自动重用,从而更容易编程和更好的性能。的线程池实现ExecutorService管理一个线程池执行任务。

应用Java并发

实际应用中经常涉及的并发需要外部交互任务(一个用户,存储,或与其他系统)是独立于你的主要处理逻辑。这种类型的应用程序很难凝聚到一个简单的例子,所以并发,人们通常使用简单的计算密集型任务,如数学计算或排序。我会用一个类似的例子。

的任务是找到最近的已知的未知的输入,在那里最近的定义为编辑距离:字符添加,删除的最小数目的变化,或需要将输入到已知的单词。我使用的是基于在一个示例代码编辑距离对维基百科的文章来计算Levenshtein距离为每个已知的单词并返回最佳匹配(或不明确的结果,如果多个已知的单词有相同的距离)。

清单1显示了用于计算Levenshtein距离的Java代码。计算生成的行和匹配两种文本的比较大小的列的矩阵,再加上一个在每个维度。为了提高效率,我们实现使用对数组大小的目标文本表示的矩阵的连续行,交换阵列中的每一次因为我需要从之前的行来计算下一行只值。

 

猜你喜欢

转载自hqcool.iteye.com/blog/2061979
今日推荐