1. 问题的提出
一台计算机为何能够执行多个程序?它们是怎么执行多个程序的?
- 电脑可以同时做很多事情,一边聊天,一边听歌,一边上网查资料等
- 原因是电脑有多个核心(脑子),一个核心可以做一件事情,多个核心就可以做多件事情
- 而多线程就是一台电脑,CPU可以同时运行两个程序(表面上),实际上是进程切换的快,第一个进程打开,第二个进程挂起,给你一种错觉
例如CPU的6核12线程,就相当于有6个工人去运行进程
2. 核心数、进程、线程
- 一个核心下有多个进程,而一个进程下又会有多个线程
3. 进程和线程的区别以及对应应用
进程和线程的区别
- 线程只是一个进程中不同执行的路径
- 进程与进程之间不会相互影响,因为它们是占有独立内存的
- 而线程是占用共同的内存,所以一个线程出问题,那这个进程下的线程都会出问题
- 多进程的程序要比多线程的程序健壮,而多线程运行效率更高,但是线程不能独立执行,必须依存在应用程序中,操作系统不会把线程看作多个独立应用
- 但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。例如很多人共同抢一双鞋,就要用到多线程
并发与并行
- 并发(Concurrent)指一个CPU需要进行多个进程,这样就需要不停的切换,让进程不断的交替执行
- 并行(Parallel)指多个CPU同时执行多个进程
4. 多线程程序含义、多线程的作用
创建多线程DemoThread
类,Alt+Insert
调出Generate
选择Override Methods
选择run():void
mainThread
和DemoThread
两个字符串交替执行
如果用.run()
的话会出现问题,死循环一直在跑,用.start()
可以多开启一个线程,然后去自动调用.run()
,再继续进行当前线程
显示的结果是两个死循环的内容在交替执行,其原因就是使用了.start()
后两个线程一直在执行
5. 多线程的执行过程
多线程的执行方式
- 一般的程序是从
main
出发,直线向下进行,只有一条主线
- 多线程在
main
主线程序遇到线程程序时会转到线程程序,并返回到主线程序中,这样main程序和线程程序同时执行
6. Runnable
前面我们创建线程单继承了Thread,无法继承别的类,因为Java不支持多继承
使用Runable
接口来创建线程,要使用其方法,必须创建Thread
对象实现
Ctrl + 左键
查看Thread源码
源码中,Thread
类就是实现了Runnable
接口,而在Thread
的构造方法中也有许多方法函数需要传递Runnable
接口类型
而我们在主函数中实现的应该是第一种传递方式,Thread
的构造方法还有很多方式,这些构造函数都有一个特点就是全部使用init
这个方法对线程进行实现
init
源码的变量注释及源码
- 在原始的init中名字是不能为空的,如果名字为空会报空指针异常,但是在其他的函数中,如果程序员不给
thread.name
赋值的话也可以自动生成一些值
- 涉及线程组相关的安全问题
- 变量的赋值和其他函数的初始化相关
下面init
方法是对上面的函数的衍生,是构造方法中使用的初始方法
7. 简化操作以及线程名
Thread
源码里面有传线程名的构造方法,要在原来线程类中自动获取我们在主线程中设置的名字,使用Thread.currentThread().getName()
方法,.currentThread()
是指当前线程,.getName()
是指获取名字
8. 抢购鞋——多线程案例
两种创建线程的方式,一种使用继承,一种使用接口实现,解决了线程名的问题,接下来我们模拟一个多线程的抢鞋程序
抢鞋的逻辑代码涵盖在线程当中,假设有10双鞋,有三个人来抢,一个线程就是一个用户,所以这就有三个名称不一样的线程名
使用Runnable
接口创建
9. 后台、守护进程的提出
电脑任务管理器
- Apps是前台进程,Background processes是后台进程也叫守护进程,这些进程在电脑开机时就被启动,这样电脑才能正常且安全的运作起来,在程序中也是同理
- 与进程同理,前台线程为用户提供服务,也有后台线程为前台线程提供的服务进行保护或者守护
后台线程的创建过程
- 创建一个
DaemonThread
,实现Runnable
接口
- 重写
run()
方法
- 在运行类中创建先一个
DaemonThread
,再用Thread
用来实现DaemonThread
- 最后调用
setDaemon(true)
设置成后台守护线程,.start()
开启线程