在进行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
}
}
- 继承Thread, 重写run 方法
- 创建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
}
}
- 实现Runnable 接口
- 重写run 方法
- 放入new Thread(new Runnable());
- 调用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接口
进程与线程区别
资源分配和调用
在传统操作系统中,进程是系统资源分配和调度分派的基本单位,为实现系统的并发提供了可能;
在现代操作系统中,进行是系统资源分配的基本单位,线程是调用分派的基本单位,为实现进程中实现并发提供了可能;稳定性
进程出现问题,不会影响其他进程;
线程出现问题,会导致整个进程出错,其他线程也会中断;资源共享
进程有自己的地址空间,CUP分配的资源, 但进程间,资源不可共享相互独立,但可以访问
线程没有独立的地址空间,依赖进程而存在,并且使用的系统资源很少,共同享有进程占有的资源和地址空间调度切换开销
进程的创建和销毁不仅需要保存寄存器和栈信息,还需要资源的分配回收以及页调度,开销较大
线程只需要保存寄存器和栈信息,开销较小同步
进程同步简单,因为资源不可同享
当线程需要同时访问一个资源时,此时同步问题就需要好好分析
疑问,多线程一定比单线程优吗?
还是具体问题具体分析比较好:
对于单一任务 或者 处理时间短的 或者启动频率高的,此时多线程的使用可能会增加系统开销。
对于多任务时 响应时间较长的,防止进入等待状态的,比如要显示UI,访问网络,数据读写,此时多线程是更优的。
但是多线程能够提升程序性能,但是相对于单线程来说,它的编程要复杂地多,要考虑线程安全问题。
~看到新问题会继续补充