Java并发系列教程之进程与线程解析

74 阅读3分钟

进程

•程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存,在指令运行过程中还需要用到磁盘、网络等设备,进程就是用来加载指令、管理内存、管理IO等操作。

•当一个程序被运行,从磁盘加载这个程序的代码至内存,这是就开启了一个进程。

•进程就可以视为程序的一个实例,大部分程序可以同时运行多个实例进程(例如记事本等),也有的程序只能启动一个实例进程(例如网易云音乐等)。

线程

•一个进程之内包含一到多个线程。

•一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行。

•Java中,线程作为最小调度单位,进程作为资源分配的最小单位。

二者对比

•进程基本上相互独立,而线程存在于进程中,是进程的一个子集。

•进程拥有共享的资源,如内存空间等,供其内部的线程共享。

•进程间通信较为复杂

1.同一台计算机的进程通信成为IPC(Inter-process communication)

2.不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如HTTP

•线程通信相对简单,因为他们共享进程的内存,例如多个线程可以访问同一个共享变量。

•线程更轻量,线程上下文切换成本一般要比进程上下文切换低。

并行与并发

单核CPU下,多个线程实际还是串行执行,操作系统中有一个组件叫任务调度器,将CPU的时间片(windows下时间片最小约15毫秒)分给不同的程序使用,只是由于CPU在线程间(时间片很短)的切换非常快,人类感觉是同时运行的,总结为一句话就是:微观串行,宏观并行。

一般会将这种线程轮流使用CPU的做法成为并发(concurrent)。

CPU时间片1时间片2时间片3时间片4
core线程1线程2线程3线程4

表1





图1

多核CPU下,每个核(core)都可以调度运行线程,这时候线程可以是并行(parallel)。

CPU时间片1时间片2时间片3时间片4
core1线程1线程1线程3线程3
core2线程2线程4线程2线程4

表2





图2

引用Rob Pike的一段描述:

•并发(concurrent)是同一时间应对(dealing with)多件事情的能力。

•并行(parallel)是同一时间动手做(doing)多件事情的能力。

创建和运行线程

方法一、直接使用Thread

//创建线程对象 Thread thread = new Thread(){ @Override public void run() { //TODO doing 线程要执行的任务 } }; //启动线程 thread.start();

方法二、使用Runnable配合Thread

把【线程】和【任务】分开

•Thread代表线程

•Runnable可运行的任务(线程要执行的代码)

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        //TODO doing 线程要执行的任务
    }
};
//创建线程对象
Thread thread = new Thread(runnable);
//启动线程
thread.start();

方法三、FutureTask配合Thread

FutureTask能够接受Callable类型的参数,用来处理有返回结果的情况

FutureTask<Object> task = new FutureTask<>(new Callable<Object>() {
    @Override
    public Object call() throws Exception {
        //TODO doing 线程要执行的任务,并返回任务结束的结果
        return null;
    }
});
//创建线程对象
Thread thread = new Thread(task);
//启动线程
thread.start();
try {
    //当前线程会阻塞等待子线程任务task返回结果
    Object result = task.get();
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

作者:刘跃明