进程是资源分配的最小单位,线程是CPU调度的最小单位
1、进程: 运行起来的程序。
进程通信:网络连接,管道(铁路),信号量,共享内存+同步机制(锁)
进程是应用程序运行的载体。一旦程序被载入到内存中并准备执行,它就是一个进程。进程是一种抽象的概念,进程是资源分配的基本单位,又是调度运行的基本单位,是系统中的并发执行的单位。
进程是拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每个进程有各自独立的一块内存(地址空间),使得各个进程之间内存地址相互隔离。
(1)进程一般由程序,数据集合和进程控制块三部分组成:
程序:用于描述进程要完成的功能,是控制进程执行的指令集;
数据集合:是程序在执行时所需要的数据和工作区;
程序控制块:包含进程的描述信息和控制信息是进程存在的唯一标志
(2)进程具有的特征:
动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;
并发性:任何进程都可以同其他进行一起并发执行;
独立性:进程是系统进行资源分配和调度的一个独立单位;
结构性:进程由程序,数据和进程控制块三部分组成
(3)进程状态转化图:
2、线程 : 单个进程中执行中每个任务就是一个线程 , 线程是进程中执行运算的最小单位。
1、组成进程的个体
2、cpu运行基本单位
3、线程只是进程的一个入口,线程共享进程中的资源。
4、局部变量线程私有的,栈(方法),程序计数器(记录下一条要执行的指令)
5、通信:共享变量(可以是mysql 文件 全局变量)+同步机制(锁)
随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID,当前指令指针PC,寄存器和堆栈组成。而进程由内存空间(代码,数据,进程空间,打开的文件)和一个或多个线程组成。
3、进程和线程区别联系:
(1)进程和线程的关系:
1、一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
2、资源分配给进程,同一进程的所有线程共享该进程的所有资源。
3、CPU分给线程,即真正在CPU上运行的是线程。
(2)进程与线程的区别
1. 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
2. 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线
3. 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见;
4. 调度和切换:线程上下文切换比进程上下文切换要快得多
(3)进程和线程的区别
1、划分尺度:线程更小,所以多线程程序并发性更高;
2、资源分配&处理器调度:进程是资源分配的基本单位,线程是处理器调度的基本单位。
3、地址空间:进程拥有独立的地址空间;线程没有独立的地址空间,同一进程内多个线程共享其资源;
4、执行:每个线程都有一个程序运行的入口,顺序执行序列和程序的出口,但线程不能单独执行,必须组成进程,一个进程至少有一个主线程。简而言之,一个程序至少有一个进程,一个进程至少有一个线程。
(4)进程和程序区别
1、进程是一个动态概念,程序是静态概念。进程 存在于程序的执行过程中。
2、进程具有并发特性,程序没有。
3、进程间相互制约,而程序没有。资源的共享和竞争造成进程相互制约。
4、进程与程序之间不是一对一关系。
一个程序执行在不同的数据集上就成为不同的进程,可以用进程控制块来唯一地标识每个进程。一个进程肯定有一个与之对应的程序,而且只有一个。而一个程序有可能没有与之对应的进程**(因为它没有执行),也有可能有多个进程与之对应(运行在几个不同的数据集上)。
4、并发与并行:
5、为何不使用多进程而是使用多线程?
线程廉价,线程启动比较快,退出比较快,对系统资源的冲击也比较小。而且线程彼此分享了大部分核心对象(File Handle)的拥有权
如果使用多重进程,但是不可预期,且测试困难
1)需要频繁创建销毁的优先用线程
原因请看上面的对比。这种原则最常见的应用就是Web服务器了,来一个连 接建立一个线程,断了就销毁线程,要是用进程,创建和销毁的代价是很难承受的
2)需要进行大量计算的优先使用线程
所谓大量计算,当然就是要耗费很多CPU,切换频繁了,这种情况下线程是最合适的。这种原则最常见的是图像处理、算法处理。
3)强相关的处理用线程,弱相关的处理用进程
什么叫强相关、弱相关?理论上很难定义,给个简单的例子就明白了。一般的Server需要完成如下任务:消息收发、消息处理。“消息收发”和“消息处理”就是弱相关的任务,而“消息处理”里面可能又分为“消息解码”、“业务处理”,这两个任务相对来说相关性就要强多了。因此“消息收发”和“消息处理”可以分进程设计,“消息解码”、“业务处理”可以分线程设计。当然这种划分方式不是一成不变的,也可以根据实际情况进行调整。
4)可能要扩展到多机分布的用进程,多核分布的用线程
原因请看上面对比。
5)都满足需求的情况下,用你最熟悉、最拿手的方式
至于“数据共享、同步”、“编程、调试”、“可靠性”这几个维度的所谓的“复杂、简单”应该怎么取舍,我只能说:没有明确的选择方法。但我可以告诉你一个选择原则:如果多进程和多线程都能够满足要求,那么选择你最熟悉、最拿手的那个。需要提醒的是:虽然我给了这么多的选择原则,但实际应用中基本上都是“进程+线程”的结合方式,千万不要真的陷入一种非此即彼的误区。
6、java创建线程
主线程:main
子线程:创建方法有四
(1):继承Thread类 不能再继承别的类 重写run()方法
class MyThreadTest extends Thread{
@Override
public void run() {
super.run();
System.out.println("MyThread: "+Thread.currentThread().getName());
}
}
public class MyThread {
public static void main(String[] args) {
MyThreadTest myThreadTest1 = new MyThreadTest();
// myThreadTest.setName("oo7:");//定义线程名字
// myThreadTest.start();//调用start方法才算是真正开启一个线程,
// myThreadTest.run();// 调用run意思是运行了一个普通类里的方法。
System.out.println(myThreadTest1.currentThread().getName());
for (int i = 0; i < 100; i++) {
MyThreadTest myThreadTest = new MyThreadTest();
myThreadTest.setName("nihao-"+i);
myThreadTest.start();
}//会被线程池代替
System.out.println(myThreadTest1.currentThread().getName());
}
}
(2):实现Runnable接口 可以继承别的类和接口 重写run()方法
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("Thread :" + Thread.currentThread().getName());
}
}
public class MyRunnableDemo {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread t = new Thread(runnable,"pipip-");
t.start();
t.run();
}
}
(3):实现Callable接口 重写call()方法,有返回值
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("Thread :"+Thread.currentThread().getName());
return 1;
}
}
public class MyCallAbleDemo {
public static void main(String[] args) {
MyCallable callable = new MyCallable();
FutureTask<Integer> task = new FutureTask<Integer>(callable);
//task 是为了获取返回值
Thread t = new Thread(task);
t.start();
try {
Integer i = task.get();
System.out.println("i = " +i);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
(4)线程池
7、run和start方法区别
start() 方法:
1、启动线程
2、使线程状态从NEW变成RUNNABLE状态。
3、内部调用Runnable接口的run()方法。
run() 方法:
run()方法是Runnable接口的一个抽象方法,由java虚拟机直接调用的,不会创建的新线程。
区别:
1、定义的地点不一样:
start()方法在java.lang.Thread类中定义,而 run()方法在java.lang.Runnable接口中定义,必须在实现类中重写。
2、 当程序调用start()方法时,会创建一个新线程,然后执行run()方法。
当直接调用run()方法,则不会创建新的线程,run()方法将作为当前调用线程本身的常规方法调用执行,并且不会发生多线程(Thread.currentThread().getName())打印结果为main)。
3、start()方法不能多次调用,否则抛出java.lang.IllegalStateException,而run()方法可以进行多次调用,因为它只是一种正常的方法调用。
8、三种实现方式的区别
1、Callable和Runnable最后都是调用Thread的start方法启动。
2、使用Thread是继承他的类,这样就不能继承别的类了(单继承),而用runnable和callabe是实现接口,这样更灵活。
3、callable是重写call()方法,而且他有返回值