基本概念
程序:是为了完成某个特定任务,使用某种计算机语言编写的一组指令的有序集合
进程:是具有一定独立功能的程序的运行过程,是系统进行资源分配和任务调度的一个独立单位
进程是程序的一次执行过程,或是正在运行的一个程序。是动态的过程;有它自身的产
生、存在和消亡的过程
线程:是进程中的一个独立执行线索,是cpu调度和分配的基本单位,自己基本上不拥有系统资源
单线程:同一时刻,只允许执行一个线程
多线程:同一时刻,可以执行多个线程,如:一个qq进程可以同时打开多个聊天窗口,一个迅雷
进程可以同时下载多个文件
并发:cpu调度算法,同一时刻,多个任务交替执行,使用户看上去是在同时执行,实际从cpu操
作层面上不是真正的同时执行
并行:多个cpu或者多台机器同时执行一段处理逻辑,同一时刻,多个任务同时执行
进程:
每个进程都有独立的代码和数据空间,进程切换成本较高,一个进程可以包含1-n个线程,进程是资源分配的最小单位
同一个进程中的线程可能会有共享代码,可以共享进程的数据空间,每个线程有独立的运行栈和程序计数器,线程切换的开销很小,线程是cpu调用的最小单位。
启动进程:
进程和线程一样分5个阶段:创建、就绪、运行、阻塞和终止
cmd/c启动运行名称后会关闭窗口
启动方法1:
ProcessBuilder builder=new ProcessBuilder("cmd","/c","ipconfig/all");//构建进
程的对象
Process process=builder.start(); //启动进程
//获取ipconfig/all命令的执行结果
BufferedReader reader=new BufferedReader(new
InputStreamReader(process.getInputStream(),"GBK"));//用于获取ipconfig/all进程的
执行结果
String tmp=null;
while((tmp=reader.readLine())!=null)
System.out.println(tmp);
启动方法2:
String cmdStr="cmd /c ipconfig/all";
Process process=Runtime.getRuntime().exec(cmdStr);
BufferedReader reader=new BufferedReader(new
InputStreamReader(process.getInputStream(),"GBK"));//用于获取ipconfig/all进程的
执行结果
String tmp=null;
while((tmp=reader.readLine())!=null)
System.out.println(tmp);
进程三大特征:
独立性:进程是一个能够独立运行的基本单位,是系统资源分配和调度的独立单位
动态性:进程·的实质就是程序的一次执行过程,动态的产生、动态的消亡
并发性:任何进程都可以同其他进程一起并发执行
异步性:
结构特征:进程有程序、数据和进程控制块三部分构成
僵尸进程和孤儿进程
僵尸进程就是当子进程比父进程先结束,但是父进程没有回收子进程,并没有释放子进程所占用的资源。
1.父进程先退出,子进程会给init进程接管,子进程退出后init会回收子进程所占用的相关资源
2.是对系统资源的浪费,测试人员有业务发现,需要处理解决
孤儿进程就是当父进程退出,而多个子进程还在运行
1.孤儿进程会被init进程管理,并由init进程对其进行状态收集工作
2.没有什么危害
主线程:
线程是进程中的一个实体,用来描述进程的执行,负责执行包括在进程内部地址空间中的代码
创建一个进程时,它的第一个线程称为主线程,是由系统自动生成的
1.主线程是产生其它子线程的线程
2.通常都是最后执行完成的,因为还需要它来执行各种关闭动作。
public class Test1{
public static void main(String[] args)throws Exception{ //当java程序运行
时,首先创建一个运行main方法的线程---主线程
System.out.println(Thread.currentThread().getName());//获取运行main方
法的线程名称
//在主线程内容可以启动子线程
Thread t=new Thread(){
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
t.start();//启动线程t的运行
System.in.read(); //阻塞当前main线程
}
}
进程中线程之间的关系
一个进程中的线程之间没有父子关系之分,都是平级关系,所有线程都是一样的,一个退出不会影响另外一个。但是在主线程中执行完毕可以使用System.exit(int)强制结束当前进程,exit方法会使整个进程停止,那么所有的线程都会自动退出
进程 vs 线程
1.一个线程只能属于一个进程,而一个进程可以包含多个线程,至少有一个线程(主线程)
2.资源调度和分配给进程,同一进程中的所有线程共享该进程的所有资源
3.线程在执行过程中,共享数据一般都需要进行协作同步
4.CPU分给线程,真正在处理机上运行的是线程
5.线程是指在进程内部的一个执行单元,也是进程内的可调度的实体,两者都是动态的概念
进程和线程最大的区别在于:进程是由操作系统来控制的,而线程是由进程来控制线程本身的数据通常只有寄存器数据以及当前程序在运行时使用的堆栈,所以线程的切换比进程切换的成本要小的多。多个进程的内部数据和状态是完全独立的,而同一个进程内的多线程共享一块内存空间和一组系统资源,有可能互相影响。
多线程
线程是进程中的一个执行实体,用来描述进程的执行,负责指向包括在进程内部地址空间中的代码
1.在Java中一个应用可以包含多个线程,每个线程执行特定任务,可以与其它线程并发执行
2.引入多线程的目标在于减少CPU空转时间,提供CPU的利用率,java多线程提供了一个编程模型隐藏CPU在多任务间切换的实现细节,不需要修改代码就可以实现跨多CPU、多核的处理器
提高吞吐量,充分利用cpu资源,减少cpu空转时间
伸缩性,可以通过CPU核数提升性能。使用多线程并不能提高硬件的性能
注意:在很多情况下可以显式地使用线程以提高程序执行的性能、响应速度。要用多线程的主要原因是
运行过程中需要处理大量的IO操作或者需要有较多的等待时间,比如读写文件、视频图像的采集等。
问题1:多线程机制会提高程序的运行效率?
不一定。如果针对密集型计算的应用应该使用单线程,避免多线程中的切换问题,反而引入多线程会影响执行效率资源限制的挑战。在并发编程时需要考虑到资源上的限制,如果受制于资源,整体程序的速度肯定会降低
解决方案:
1.对于硬件资源的限制,可以使用集群来执行程序
2.对于软件资源上的限制,可以通过复用资源的方式提高,例如复用数据库连接
3.可以根据资源的限制,灵活的调整并发度
多线程优点 |
多线程的缺点 |
1.在多任务中,各个进程需要分配各自独立的地址空间;多线程可共享相同的地址空间并且分享同一个进程 2.进程间调用涉及的开销比线程通信多 3.线程间的切换成本比进程间切换的成本低 |
设计更复杂,上下文切换开销,增加资源消耗 |
线程
线程是比进程更小的执行单位
1.线程:轻量级进程LWP,系统负担小,主要是CPU分配
2.线程不能独立存在,必须存在于进程中
3.每个线程也都有它产生、存在和消亡的过程,也是一个动态的概念
4.一个线程有它自己的入口和出口以及一个顺序执行的代码序列
为什么使用线程
1.减轻编写交互频繁、涉及面多的程序的困难
2.改善应用的吞吐量
3.有多个处理器的i同可以并发/并行运行不同的线程
多线程
多线程是指同时存在几个执行体,按几个不同的执行线索共同工作的情况
1.多线程实现单个进程中的并发计算,JDK1.8开始提供了针对并行支持
2.各个线程间共享进程空间中的数据,并可以利用共享单元实现数据交换、实时通信与
必要的同步操作
多线程的程序可以更好的表述和解决现实世界中的具体问题,是计算机应用开发和程序设计的一个必然趋势
优点:解决了多部分同时运行的问题
缺点:线程太多会有效率反而降低的问题,一般计算密集型应用不适合多线程
java与多线程
Java语言内置了对多线程的支持,可以很方便地开发出具备多线程功能,同时处理多个任务的应用。每个Java应用程序都有一个隐藏的主线程
1.Application main方法
2.Applet小应用程序,主线程指挥浏览器加载并执行java小程序
要求:左手画条龙,右手画彩虹
方式1:继承Thread类,覆盖定义run方法,run方法中就是具体的处理逻辑
方式2:实现Runnable接口定义run方法,run方法中就是具体的处理逻辑
public class Test2{
public static void main(String[] args){
Thread t1=new LeftThread(); //构建线程对象
t1.start(); //启动线程的执行,注意必须使用start方法,而不是直接调用run方法
Thread t2=new Thread(new RightThread()); //构建线程对象
t2.start();
}
}
public class LeftThread extends Thread{
public void run(){
for(int i=0;i<50;i++){
System.out.println("画条龙...."+i);
//停止运行,阻塞300ms
try{
this.sleep(300);
} catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
public class RightThread implements Runnable{
public void run(){
for(int i=0;i<50;i++){
System.out.println("画彩虹...."+i);
//停止运行,阻塞300ms
try{
Thread.currentThread() //获取当前正在运行的线程对象
.sleep(300); //阻塞等待300ms
} catch(InterruptedException e){
e.printStackTrace();
}
}
}
}