1.0 Java并发编程基本知识介绍
1、什么是并发?
用户通常认为计算机在同一时刻可以做多个事情是理所当然的事情。
例1:例如你可以一边听音乐,一边玩游戏,同时还通过聊天工具和别人聊天。假设你使用的qq音乐播放器在听音乐,玩的是qq斗地主游戏,使用qq和别聊天,那么这实际上是三个不同的软件在同时运行,完成三个不同的事情。
例2:当然我们也不能否认,在一个软件内,同时可以完成以上三个事情:聊天、游戏和音乐。例如你在玩qq斗地主,以便在打牌,播放了背景音乐,同时你还可以和其他牌友聊天,发一句"我等的花儿也谢了",这实际上是一个软件可以同时完成三个不同的事情。
不管是那种情况,我们应该知道的是,并发指的是在同一时刻执行多个任务。
2、进程与线程
进程:进程通常是程序、应用的同义词。不过,用户所看到的一个单独的应用事实上可能还会有一系列的协作进程(cooperating processes
),例如Linux上就可以通过fork创建一个进程副本。最简单的情况下,一个应用就是一个进程。
上例1中,我们使用了启动了三个不同的应用完成三个不同的事情,你可以认为打开了一个软件就相当于在操作系统中开启了一个进程。需要注意的是,软件本身就是一个文件而已,当你启动了之后,它才会成为操作系统中的一个进程。操作系统会给进程分配运行时需要的资源,例如内存。为了方便进程之前的通信,大多数操作系统有支持进程之间相互通信(Inter Process Communication ,IPC)的措施,例如管道、socket等。IPC不仅支持同一个操作系统上进程的通信,也支持不同操作系统上进程的通信。例如,我们通过IE浏览器访问网页,IE浏览器就是我们本机上的一个进程,而远程服务器又是另外一个进程,本地浏览器进程向远程服务器发送网页请求,远程服务器进程将数据返回给浏览器。
大部分Java虚拟机的实现都是作为单进程运行的,也就是说,启动Java虚拟机的时候,只会启动一个进程。在Java应用中,我们可以通过ProcessBuilder来创建附加的进程。
前面已经提到,一个操作系统可以同时运行多个进程,如果你使用的操作系统是windows,你可以通过任务管理器来查看现在你的电脑上到底启动了多少个用户进程,以下是本人现在操作系统中启动进程状态,总共有108
个,你的可能与我的不一样,因为我们电脑上装的软件可能不一样,而且即使完全一样,可能我打开了这个软件而你没有:
线程:我们已经提到,即使是在一个软件内,我们也能同时干多个事,这些不同的功能可以同时进行,是因为在进程内使用了多个线程。线程有时又称之为轻量级进程
。但是创建一个线程要消耗的资源通常比创建进程少的多。一个进程内的多个线程会共享进程的资源,同时也会有自己私有的资源。
线程必须存在于进程中,每个进程至少要有一个线程作为程序的入口。线程是可以并发执行的,所以我们在一个软件内也可以同时干多个事。操作系统上通常会同时运行多个进程,每个进程又会开启多个线程。
3、单核与多核
单核
现在的计算机基本上都是多核计算机,单核的估计你想买也买不到了。那么单核与多核有什么区别呢?
事实上,从计算机发展历史上来说,最早是单核CPU时代。在单核CPU早期,在任意时刻只能同时运行一个进程,注意这不是因为只有一个CPU,而是操作系统的限制,例如早期的DOS操作系统只能同时运行一个任务。之后发展到多任务阶段,计算机能并行执行多任务或多进程,同样请你注意的是,支持多个任务同时运行,是因为操作系统更加先进了(不否认CPU也在进化),支持在一个CPU中同时运行多个任务,例如Unix、Linux、Windows。
需要注意的是这并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个CPU,并交由操作系统来完成多任务间对CPU的运行切换,以使得每个任务都有机会获得一定的时间片
运行。因为切换的速度足够快,所以感觉上就像是多个软件在同时运行。
再后来发展到多线程技术,使得在一个程序内部能拥有多个线程并行执行,这让我们可以在一个程序内同时进行多个任务。
类似的,当一个CPU在运行某一个进程的时候,也并不是同时执行多个线程,还是因为不同的线程执行切换的非常快,让我们感觉好像多个线程在同时运行。
事实上,在一个单核的CPU上,在任一时刻,只有一个进程的中一个线程在运行。笔者就曾经遇到过这样的面试题,什么情况下,一个计算机中任一时刻只会有一个线程在运行。这个问题很简单,只要你的CPU是单核的就行了。
多核
单核CPU之所以同一时刻只能运行一个线程,是因为一个CPU同一时刻只能处理一个指令。只有在CPU时多核的情况下,才能实现真正意义上的并行执行。如果你的CPU是双核的,那么就可以同时运行2个线程,如果是4核的,就可以同时运行4个线程...
4、Java与多线程
作为开发者,我们关心的是如何让我们的开发的应用具有并行处理任务的能力,因此我们通常关心的是多线程。
Java是最先支持多线程的开发的语言之一,Java从一开始就支持了多线程能力。而Java的并发编程是非常具有挑战性的,这也是我想为Java并发技术而写这篇系列的原因。作为对自己的笔记,和对其他Java开发的追随者都可获益的。
多线程比多任务更加有挑战。从进程的层面来说,当启动一个进程的时候,操作系统会分配给这个线程一定的内存空间,每个进程只要操作各自的内存空间即可。而多线程是在同一个程序内部并行执行,因此会对相同的内存空间进行并发读写操作。这可能是在单线程程序中从来不会遇到的问 题。其中的一些错误也未必会在单CPU机器上出现,因为两个线程从来不会得到真正的并行执行。然而,更现代的计算机伴随着多核CPU的出现,也就意味着不 同的线程能被不同的CPU核得到真正意义的并行执行。