目录
只针对OS级别的线程:OS针对同一个进程下的线程实现“连坐”机制,一旦一个线程异常退出,OS会关闭该线程所在的整个进程
执行流:拥有独立pc的一套指令,不同的执行流从现象上看起来是完全独立的
1.线性地址(虚拟地址):物理地址
物理地址:真实内存中的地址
线性地址:物理地址被OS进行转换后的一个地址
引入线性地址这个概念之后,程序员不需要再考虑这个复杂性了。
MMU来管理复杂性
2.进程间通信(IPC)
理论上,进程之间是独立的,但实际上,往往是多个进程之间相互配合,来完成复杂的工作。
例如:通过workbench和mySql服务器进程进行通信,来实现的数据的增删查改
所以,有了进程之间交换数据的必要性了。
当下问题:OS进行资源分配是以进程为基本单位进行分配的,包括内存。分配给A进程的内存不会分配给B进程。所以,进程A表之间直接通过内存来进行数据交换的可能完全不存在了
所以OS需要提供一套机制,用于让A、B之间进行必要的数据交换——进程间通信
进程间通信的常见方式:
1.使用管道(pipe) Linux时接触
2.消息队列(message queue)
3.信号量(semaphore)
4.信号(singal) Linux时接触
5.共享内存(shared memory)
6.网络(nextwork)——mysql和workbench通信的方式
内存管理中主要研究的问题:
1.管理哪些内存已经被分配,那些内存暂时未被分配
2.已经分配出去的内存,何时进行回收、如何进行回收
3.物理地址 <->线性地址相互转换
4.内存碎片
1.现在介绍的都是OS系统层面地线程
thread(线)
2.进程(process)和线程(thread)的关系
进程和线程是1:m的关系,一个线程一定属于一个进程,一个进程下可以允许有多个线程
一个进程内至少有一个线程,通常被这个一开始就存在的线程,成为主线程(Main thread)
主线程和其他线程之间地位是完全相等的,没有任何特殊性
3.为啥引入线程thread的概念?
由于进程这一概念天生就是资源隔离的,所以进程挚爱金进行数据通信注定是一个高成本的工作
现实中,一个任务需要多个执行流一起配合完成,是非常罕见地
所以,需要一种方便数据通信的执行流概念出来,线程就承担了这一职责。
4.什么是线程?
线程是OS进行调度的基本单位
线程变成了独立执行流的承载概念,进程退化成只是资源(不含CPU的承载单位)
比如:
运行一个程序,没有线程之前,OS创建进程,分配资源,给定一个唯一的PC,进行运行
有了线程之后,OS创建线程,分配资源。创建线程(主线程),给定一个唯一的PC,进行运行
高级语言中的语句经过编译之后会变成一条或者多条指令
执行流:拥有独立PC的一个或者一组指令
进程:OS进行资源分配的基本单位(不包含CPU资源)
线程:OS进行调度的单位(包含CPU资源)
程序的一次执行过程表现为一个进程,main所在的线程就是主线程,主线程可以手动的创建其他线程,我们来试着跑一下两个线程:
public class AboutThread {
static class SomeThread extends Thread{
@Override
public void run() {
int i =0;
while(true){
System.out.println("我是另一个线程(执行流B)" + (i++));//语句1
try {
TimeUnit.MILLISECONDS.sleep(139); //ms 语句2
//millisecond是千分之一秒,毫秒
} catch (InterruptedException e) {
// e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
//在主线程中,利用SomeClass对象,创建出一个新的线程出来
SomeThread st = new SomeThread();
st.start();
int i =0;
while(true){
System.out.println("我是主线程(执行流A)" +(i++));//语句1
try{
TimeUnit.MILLISECONDS.sleep(257);//语句2
} catch (InterruptedException e) {
}
}
}
}
运行结果如图:
只针对OS级别的线程:OS针对同一个进程下的线程实现“连坐”机制,一旦一个线程异常退出,OS会关闭该线程所在的整个进程
接下来的所有学习针对的都是JVM中规定的线程
不同JVM有不同的实现,他们的外在表现基本一致,除了极个别的现象
我们使用的HotSpot实现(JVM),使用一个OS原生线程来实现一个Java线程
(Java线程,一个想爱你成异常关闭,不会连坐)
Java中的进程由于有JVM的存在,所以使得Java中做多进程级别的开发基本很少。Java中的线程还克服了操作系统线程的很多缺点。所以,在Java开发中,我们使用多线程模型来进行来发,很少使用多进程模型。
1.Java线程在代码中是如何体现的?
java.lang.Thread类(包括其子类的)一个对象
2.如何在代码中创建线程(最基本的方式)
Thread 线程
Runnable 让这个线程去完成的工作(任务)
a.通过重写Thread类,并且重写run方法
实例化该类的对象 ->Thread对象
public class MyFirstThreadClass extends Thread{
public MyFirstThreadClass(){
System.out.println("可以正常使用构造方法之类的");
}
@Override
public void run() {
//这个方法下写的所有代码,如果正确创建线程的话,都会运行在新的线程执行流中
System.out.println("我的第一个线程");
}
}
public class Main {
public static void main(String[] args) {
MyFirstThreadClass t = new MyFirstThreadClass();
//t指向了一个创建出来的线程对象
//线程创建好了,但并没有运行起来
}
}
b.通过实现Runnable接口,并且重写run方法(创建一个任务,把任务分配给线程)
实例化Runnable对象,利用Runnable对象去构建一个Thread对象
public class MyFirstTask implements Runnable{
@Override
public void run() {
System.out.println("这是我的第一个任务的第一句话");
}
}
public class Main {
public static void main(String[] args) {
MyFirstTask task = new MyFirstTask();
//创建了一个任务对象
Thread t = new Thread(task);
}
}
3.启动线程
当手中有一个Thread对象时,调用其start()方法
注意:1.一个已经调用过start()不能再调用start()了,再调用就会有异常发生
t.start()只允许工作在“新建”状态下
2.千万不要调成run()
调用run方法,就和线程没关系了,完全是在主线程中运行代码
我们通过Thread对象控制线程的一切
Thread对象可以看做银行卡
JVM(HotSopt: 内部维护者关于线程的其他数据 ,看做一般商业银行
OS内部:实现java线程的OS线程的相关数据,看做中国人民银行
怎么理解t.start()做了什么?
把线程的状态从新建变成就绪状态,不负责分配CPU
线程把加入到线程调度器(不区分是OS还是JVM实现的)的就绪队列中,等待被调度器选中喷配CPU
从子线程进入到就绪队列的这一刻起,子线程和主线程在地位上就完全平等了,
但大概率是主线程,为什么?
主线程刚执行完t.start()就马上发生线程调度的概率不大,所以,大概率还是t.start()的下一条语句就先执行了。
什么时候子线程中的语句会先执行?
1.非常碰巧的在t.start()之后,sout之前,发生了一次线程调度
2.3.主线程的状态从运行变成就绪,主线程不再持有CPU,意味着主线程的下一条语句不再执行
调取时,选中子线程调度,子线程的状态从就绪变成运行
子线程池有了CPU,所以,执行到子线程的语句
从此刻开始,我们的代码都是一样的,但是结果充满了随机性。
什么情况下会出现线程调度(开始一个新的线程分配CPU)?
参照web---2.系统_mmmenxj的博客-优快云博客进程的分区