Java并发性是一个涵盖Java平台上的多线程,并发和并行性的术语,包含了Java并发工具、问题以及解决办法。这里将介绍多线程的核心概念,并发构造,并发问题,成本以及与Java中多线程相关的好处。
什么是多线程?
多线程意味着一个应用程序中执行着多个线程,就像一个独立的CPU一样。因此,多线程应用程序就像具有多个CPU同时执行应用程序不同部分的代码。
然而线程与CPU并不完全一致,通常多个线程共享单核CPU的时间片,并通过CPU完成多线程之间的上下文切换。如果有多个CPU,一个应用程序中的多线程可能会运行在不同的CPU上。
为什么使用多线程?
为什么要在应用程序中使用多线程有多个原因。 多线程的一些最常见原因是:
- 更好地利用单个CPU
- 更好地利用多个CPU或CPU内核
- 响应速度快
- 更有公平性
更好地利用单个CPU
最常见的原因之一是能够更好地利用计算机中的资源。例如,如果一个线程正在等待对通过网络发送的请求的响应,则另一线程可以同时使用CPU来执行其他操作。此外,如果计算机具有多个CPU,或者该CPU具有多个执行核心,则多线程还可以让应用程序利用这些额外的CPU核心。
更好地利用多个CPU或CPU内核
如果计算机包含多个CPU或CPU包含多个执行核心,则应用程序使用多个线程才能使用所有CPU或CPU核心。一个线程最多只能使用一个CPU,并且如上所述,有时甚至不能完全利用一个CPU。
响应速度快
例如,如果您单击GUI中的按钮,并通过网络发送请求,那么哪个线程执行此请求就很重要。如果使用的线程也正在更新GUI,则在GUI线程等待请求响应时,用户可能会遇到GUI“挂起”的情况。多,这样的请求可以由后台线程执行,因此GUI线程可以自由地同时响应其他用户请求。
更有公平性
多个线程之间公平地共享计算机资源。例如,假设一个服务器接收来自客户端的请求,并且只有一个线程来执行这些请求。如果客户端发送的请求需要很长时间来处理,那么所有其他客户端的请求都必须等待,直到一个请求完成。通过让每个客户端的请求由它自己的线程执行,那么没有单个任务可以完全独占CPU。
多线程与多任务
在过去,一台计算机只有一个CPU,一次只能执行一个程序。大多数小型计算机并没有真正强大到可以同时执行多个程序,所以没有尝试这样做。
多任务处理
后来出现了多任务处理,这意味着计算机可以同时执行多个程序(也就是任务或进程)。但这并不是“同时”。程序之间共享单个CPU。操作系统会在正在运行的程序之间切换,在切换之前每个程序都要执行一段时间。
程序不能再假定拥有所有可用的CPU时间、所有内存或任何其他计算机资源。一个“好”的程序应该释放它不再使用的所有资源,以便其他程序可以使用它们。
多线程
后来又出现了多线程,这意味着在同一个程序中可以有多个线程执行。一个执行线程可以被认为是一个执行程序的CPU。当有多个线程执行同一程序时,就像在同一程序中执行多个CPU。
多线程的难点
多线程是提高某些类型程序性能的好方法。线程在同一个程序中执行,因此同时读写相同的内存。这可能导致在单线程程序中不存在的错误。其中一些错误可能不会在单个CPU机器上看到,因为两个线程从来不会真正“同时”执行。然而,现代计算机配备了多核CPU,甚至还有多个CPU,这意味着不同的线程可以由不同的内核或cpu同时执行。
如果一个线程正在读取内存,而另一个线程写入数据到这个内存地址,那么第一个线程最后读的是什么值?结果是无法预测的,结果可能会不时改变。因此,作为开发人员,知道如何采取正确的预防措施是很重要的,如何控制线程访问共享资源,如内存、文件、数据库等。
Java多线程并发
Java从一开始就具有多线程功能。因此,Java开发人员经常面临上述问题。
本文主要关注的是Java中的多线程,但是多线程中出现的一些问题与多任务和分布式系统中出现的问题相似。因此,对多任务和分布式系统的引用也可能出现在这一方面。因此,“并发”一词而不是“多线程”。
并发模型
第一个Java并发模型假设在同一个应用程序中执行的多个线程也会共享对象。这种类型的并发模型通常被称为“共享状态并发模型”。许多并发语言构造和实用程序都设计为支持这种并发模型。
共享状态并发模型会导致很多并发问题,很难很好地解决这些问题。因此,另一种称为“无共享”或“独立状态”的并发模型变得流行起来。在独立状态并发模型中,线程不共享任何对象或数据。这避免了共享状态并发模型的许多并发访问问题。
新的、异步的“独立状态”平台和工具包,如Netty、Vert。x和Play / Akka和Qbit已经出现。新的非阻塞并发算法已经发布,新的非阻塞工具如LMax Disrupter已经添加到我们的工具包中。Java 7中的Fork和Join框架以及Java 8中的collection streams API引入了新的函数式编程并行性。