每个线程有自己的栈 stack
,记录该线程里面的方法相互调用的关系;
但是一个进程里的所有线程是共用堆 heap
的。
那么不同的进程之间是不可以互相访问内存的,每个进程有自己的内存空间 memeory space
,也就是虚拟内存 virtual memory
。
通过这个虚拟内存,每一个进程都感觉自己拥有了整个内存空间。
虚拟内存的机制,就是屏蔽了物理内存的限制。
Q:那如果物理内存被用完了呢?
用硬盘,比如 windows 系统的分页文件,就是把一部分虚拟内存放到了硬盘上。
相应的,此时程序运行会很慢,因为硬盘的读写速度比内存慢很多,是我们可以感受到的慢,这就是为什么开多了程序电脑就会变卡的原因。
Q:那这个虚拟内存是有多大呢?
对于 64 位操作系统来说,每个程序可以用 64 个二进制位,也就是 2^64
这么大的空间!
如果还不清楚二进制相关内容的,公众号内回复「二进制」获取相应的文章哦~
总结一下,在一个时间片里,一个 CPU 只能执行一个进程。
CPU 给某个进程分配资源后,这个进程开始运行;进程里的线程去抢占资源,一个时间片就只有一个线程能执行,谁先抢到就是谁的。
每个进程是独立的,进程 A 出问题不会影响到进程 B;
虽然线程也是独立运行的,但是一个进程里的线程是共用同一个堆,如果某个线程 out of memory
,那么这个进程里所有的线程都完了。
所以多进程能够提高系统的容错性 fault tolerance
,而多线程最大的好处就是线程间的通信非常方便。
进程之间的通信需要借助额外的机制,比如进程间通讯 interprocess communication
- IPC
,或者网络传递等等。
上面说了一堆概念,接下来我们看具体实现。
Java 中是通过 java.lang.Thread
这个类来实现多线程的功能的,那我们先来看看这个类。
从文档中我们可以看到,Thread
类是直接继承 Object
的,同时它也是实现了 Runnable
接口。
官方文档里也写明了 2 种创建线程的方式:
一种方式是从 Thread
类继承,并重写 run()
,run()
方法里写的是这个线程要执行的代码;
启动时通过 new
这个 class
的一个实例,调用 start()
方法启动线程。
二是实现 Runnable
接口,并实现 run()
,run()
方法里同样也写的是这个线程要执行的代码;
稍有不同的是启动线程,需要 new
一个线程,并把刚刚创建的这个实现了 Runnable
接口的类的实例传进去,再调用 start()
,这其实是代理模式。
如果面试官问你,还有没有其他的,那还可以说:
实现 Callable
接口;
但其实,用线程池来启动线程时也是用的前两种方式之一创建的。
这两种方式在这里就不细说啦,我们具体来看前两种方式。
`public?class?MyThread?extends?Thread?{
????@Override
????public?void?run()?{
????????for?(int?i?=?0;?i?<?100;?i++)?{
????????????System.out.println("小齐666:"?+?i);
????????}
????}
????public?static?void?main(String[]?args)?{
????????MyThread?myThread?=?new?MyThread();
????????myThread.start();
????????for?(int?i?=?0;?i?<?100;?i++)?{
????????????System.out.println("主线程"?+?i?+?":齐姐666");
????????}
????}
}
在这里,
main
函数是主线程,是程序的入口,执行整个程序;
程序开始执行后先启动了一个新的线程 myThread
,在这个线程里输出“小齐”;
来看下结果,就是两个线程交替夸我嘛~
Q:为啥和我运行的结果不一样?
多线程中,每次运行的结果可能都会不一样,因为我们无法人为控制哪条线程在什么时刻先抢到资源。
当然了,我们可以给线程加上优先级 priority
,但高优先级也无法保证这条线程一定能先被执行,只能说有更大的概率抢到资源先执行。
这种方式用的更多。
`public?class?MyRunnable?implements?Runnable?{
????@Override
????public?void?run()?{
????????for(int?i?=?0;?i?<?100;?i++)?{
????????????System.out.println("小齐666:"?+?i);
????????}
????}
????public?static?void?main(String[]?args)?{
????????new?Thread(new?MyRunnable()).start();
????????for(int?i?=?0;?i?<?100;?i++)?{
????????????System.out.println("主线程"?+?i?+?":齐姐666");
????????}
????}
}
这次面试我也做了一些总结,确实还有很多要学的东西。相关面试题也做了整理,可以分享给大家,了解一下面试真题,想进大厂的或者想跳槽的小伙伴不妨好好利用时间来学习。学习的脚步一定不能停止!
需要这份资料的朋友戳这里免费下载,整理出的内容大概如下:
Spring Cloud实战
Spring Boot实战
面试题整理(性能优化+微服务+并发编程+开源框架+分布式)
原文:https://blog.51cto.com/u_15308632/3294491