JAVA 多线程并发编程学习笔记 一 进程和线程

在进行java 多线程并发的学习之前,有必要了解一下进程和线程的基本知识,会有助于理解后面的学习。

并行与并发

并行: 多个事件在同一时间发生
并发: 多个事件在一时间段内发生
这里写图片描述
单CPU 仅一个处理器来完成系统操作,微观上一个时刻只能运行一个程序
多CPU 多个cpu 同时运行,实现并行,加快系统处理速度

在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单 CPU 系统中,每一时刻只能有一道程序执行,即微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。

而在多个 CPU 系统中,则这些可以并发执行的程序便可以分配到多个处理器上(CPU),实现多任务并行执行,即利用每个处理器来处理一个可以并发执行的程序,这样多个程序便可以同时执行。

目前电脑市场上说的多核 CPU,便是多核处理器,核 越多,并行处理的程序越多,能大大的提高电脑运行的效率。

注意:单核处理器的计算机肯定不能并行的处理多个任务,只能是多个任务交替的在单个 CPU 上运行。

进程

对于进程和线程的由来,可以参考一下文章
参考文章:https://www.cnblogs.com/dolphin0520/p/3910667.html

定义及理解

进程: 一个具有一定独立功能的程序关于某个数据集合的一次运行活动;比如运行在系统中的某一个程序。

进程的概念主要有两点:第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。

为解决多个任务进行时,不会因为输入读取等操作而将整个CUP处于等待状态;为此,当出现等待后,CPU可调度另一个任务进行,同时保留其他任务的状态,进度等信息,并且可实现任务的切换等操作。

java创建进程两种方式

Runtime run = Runtime.getRuntime();
//打开记事本
try {
    run.exec("control");
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

ProcessBuilder mProcessBu = new ProcessBuilder("control");
try {
    mProcessBu.start();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

线程

定义及理解

线程: 有时被称为轻量进程,是程序执行流的最小单元,一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。

在一个任务中,同样会因为进程那件事而烦恼;为此,可将一个大任务拆分为多个子任务,同时共享大任务的资源;将耗时操作放到子线程中去做,比如i/0操作,网络访问,数据计算等操作。这样可以更好的利用CPU,减少等待状态的出现。

比如:android 系统中,某app 为一个进程,当点击某按钮时,需要进行网络访问 并 将结果显示在UI 上;试想如果没有多线程,那么用户需要一直等待在这个界面,而不能进行其他操作,用户体验超级差;而有了多线程,UI 在main主线程中执行,网络访问在子线程中执行,用户除了在等待结果外,还可以进行其他操作,用户体验更佳。

java创建线程三种方式

1)extends Thread

   /**
  * @author stormxz
  * 
  * 1. 继承Thread
  * 2. 实现run 方法
  * 3. 调用start()
  */
 class ThreadDemo extends Thread {
        @Override
        public void run() {
            super.run();
            //do something
        }
 }
  1. 继承Thread, 重写run 方法
  2. 创建ThreadDemo 对象后,start
    或者将该对象作为参数传入Thread2 线程中,Thread2进行start

2)implements Runnable

/**
 * @author stormxz
 * 
 * 1. 实现Runnable 接口
 * 2. 重写run 方法
 * 3. 放入new Thread(new Runnable());
 * 4. 调用start()
 */
class RunableDemo implements Runnable {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        //do something
    }
}
  1. 实现Runnable 接口
  2. 重写run 方法
  3. 放入new Thread(new Runnable());
  4. 调用start()

3)直接new Thread(new Runnable)

new Thread(new Runnable() {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            for (int i = 0; i < 100; i++) {
                System.out.println("something" + i);
            }
        }
}).start();

与第二种类似。

由于java 不支持多继承,可根据自己情况使用
如果需要继承其他类,那么一般使用Runnable, 因为其内部实现的是接口,可扩展性强。
如果仅仅作为Thread,那么可使用extends Thread。
Thread 本身也是实现的Runnable接口

进程与线程区别

  1. 资源分配和调用
    在传统操作系统中,进程是系统资源分配和调度分派的基本单位,为实现系统的并发提供了可能;
    在现代操作系统中,进行是系统资源分配的基本单位,线程是调用分派的基本单位,为实现进程中实现并发提供了可能;

  2. 稳定性
    进程出现问题,不会影响其他进程;
    线程出现问题,会导致整个进程出错,其他线程也会中断;

  3. 资源共享
    进程有自己的地址空间,CUP分配的资源, 但进程间,资源不可共享相互独立,但可以访问
    线程没有独立的地址空间,依赖进程而存在,并且使用的系统资源很少,共同享有进程占有的资源和地址空间

  4. 调度切换开销
    进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大
    线程只需要保存寄存器和栈信息,开销较小

  5. 同步
    进程同步简单,因为资源不可同享
    当线程需要同时访问一个资源时,此时同步问题就需要好好分析

疑问,多线程一定比单线程优吗?
还是具体问题具体分析比较好:
对于单一任务 或者 处理时间短的 或者启动频率高的,此时多线程的使用可能会增加系统开销。
对于多任务时 响应时间较长的,防止进入等待状态的,比如要显示UI,访问网络,数据读写,此时多线程是更优的。

但是多线程能够提升程序性能,但是相对于单线程来说,它的编程要复杂地多,要考虑线程安全问题。

~看到新问题会继续补充

猜你喜欢

转载自blog.csdn.net/weixin_39158738/article/details/81205762