并发与并行
并发:同一时间只有一个线程在运行。 并行:同一时间多个线程同时运行。 对于单核cpu来说,所有线程都是并发的,但是cpu执行的时候被分成了很多时间片,每个时间片执行时间是固定的,且切换速度很快,所以看上去线程是并行的。 而对于多核cpu来说是支持并行的,每个运算核心实际上处理线程的方式还是和单核一样,具体线程的调度有专门的调度算法(鄙人暂时跳过)。
线程与进程
线程:cpu执行的最小单位 进程:系统进行资源分配和调度的最小单位。进程包含线程,执行进程实际上就是执行该进程所包含的线程,同一个进程的线程共享该线程的上下文环境(即内存,显卡等资源)。所以执行一个进程的完整过程就是首先加载进程的上下文环境,再执行该进程所包含的线程,然后保存上下文环境。最后切换下一个进程。 一个进程中创建线程的数量是有限的。操作系统每创建一个进程会分配一定的内存空间(据说是2G,分配原理暂时跳过),而每个进程创建线程的时候同样会给每个线程预留空间,所以每个进程最大能创建线程数则由分配给每个线程的内存大小决定(默认是2M可以修改)。 对于操作系统来说线程模型分为内核线程和用户线程(不太理解),还有一个就是在内核线程基础之上建立的轻量级进程,每一个轻量级进程都对应一个内核线程(轻量级进程是内核线程的高度抽象)。linux服务器采用轻量级进程模型,前面说到了进程是调度的最小单位,而轻量级进程和内核线程属于一对一关系,那么如果使用轻量级进程模型linux只需要一个进程层面的调度器。 而Java程序都是运行在Java虚拟机上面的,虚拟机帮我们屏蔽了操作系统的差异(不同操作系统进程模型是不一样的)。一个java程序就是一个进程,java都是单进程多线程的。Jvm中实现了一个线程调度模型:抢占式调度模型或者协同式调度模型,根据这个为多线程分配cpu空间。但实际上Java线程通过映射到系统原生线程来执行的,所以线程调度最终还是取决于操作系统。在linux系统中java进程中的线程映射成为了轻量级进程用于抢夺cpu资源,而这些轻量级进程又共享一个java进程的上下文资源。 在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程) 。用户线程一般用户执行用户级任务,而守护线程也就是“后台线程”,一般用来执行后台任务,守护线程最典型的应用就是GC(垃圾回收器)。这两种线程其实是没有什么区别的,唯一的区别就是Java虚拟机在所有“用户线程”都结束后就会退出。我们可以通过使用setDaemon()方法通过传递true作为参数,使线程成为一个守护线程。我们必须在启动线程之前调用一个线程的setDaemon()方法。否则,就会抛出一个java.lang.IllegalThreadStateException。同时可以使用isDaemon()方法来检查线程是否是守护线程。
|