- 什么是进程?什么是程序?有什么区别?
程序:数据与指令的集合,程序是静态的
进程:给程序加入了时间的概念,不同的时间进程有不同的状态
进程是动态的,就代表OS中正在运行的程序
独立性,动态性,并发性
- 什么是并行?什么是并发?
CPU:电脑的核心处理器,类似于“大脑”
并行:相对来说资源比较充足,多个CPU可以同时处理不同的进程
并发:相对来说资源比较紧缺,多个进程同时抢占公共资源,比如CPU
- 什么是线程?线程与进程有什么关系?
线程是OS能够进行运算调度的最小单位
一个进程可以拥有多个线程,当然,也可以只拥有一个线程,只有一个线程的进程被称作单线程程序
注意:每个线程也有自己独立的内存空间(应该就是在PCB里),当然也有一部分公共的空间用于保存共享的数据
4.线程有几种状态?它们是怎么转换的?
新建状态:new–申请PCB,进行资源的分配
就绪/可运行状态:万事俱备只欠CPU,其实是将创建好的线程对象加入到就绪队列中,等待OS选中,这个选择我们是控制不了的
执行/运行状态:就绪队列中的线程被OS选中了,正在执行
注意:只有就绪状态才能切换成执行状态
阻塞状态:线程在执行中遇到了问题:
锁阻塞、休眠阻塞、等待阻塞…问题解决后再加入到就绪队列中
终止状态:线程成功执行完毕,释放资源
#################################################################
构造方法摘要
Thread() //创建一个新的线程对象,名字是系统自定义的
分配新的 Thread 对象。
Thread(String name) //与上面功能一致,还可以自定义线程名
分配新的 Thread 对象。
Thread(Runnable target) //创建一个线程对象,参数为接口Runnable的实现类
分配新的 Thread 对象。
Thread(Runnable target, String name) //与上面功能一致,还可以自定义线程名
分配新的 Thread 对象。
2.多线程实现方案总结:
多线程实现的方案一:继承
1.自定义一个类extends Thread
2.重写run()里面写业务
3.创建线程对象
4.调用start()
注意:可以通过调用父类Thread的含参构造Thread(String name)
给自定义线程对象起名字,调用方式:super(name);
多线程实现的方案二:实现
1.自定义一个类implements Runnable
2.实现接口中未实现的run()
3.打印线程名称:Thread.currentThread().getName()
4.创建目标业务对象–接口实现类的对象–包含的是我们的业务
5.创建线程对象–Thread t1 = new Thread(target);
目的:为了把实现类与Thread建立关系,原因是想用Thread的start()
6.通过线程对象调用start(),把线程对象加入就绪队列
虽然方案二写法较为复杂,但是方案二的优点如下:
耦合性不强,没有继承,后续仍然可以继承
(包证业务不会出现偏差,因为一堆人都接统一收同一个业务,而非一个个安排)
采用实现接口的方式,后续仍然可以实现其他接口
可以给所有线程对象统一业务,业务保持一致
面向接口编程,代码更高级
(避免重构-这个过程消耗资源巨大)
一个类可以挂一大堆的接口
比如:航空母舰 implements 弹射器,甲板,舰载机,塔台,反应堆…
面向接口编程开发------>对代码架构的解耦和扩展
我们在设计一个软件的代码架构时,我们都希望事先约定好各个功能的接口(即:约定好接口签名和方法),实际开
发时我们只需要实现这个接口就能完成具体的功能!后续即使项目变化、功能升级,程序员只需要按照接口约定重新
实现一下,就可以达到系统升级和扩展的目的!
耦合是指两个或两个以上的体系或两种运动形式间通过相互作用而彼此影响以至联合起来的现象。 解耦就是用数学方法将两种运动分离开来处理问题,常用解耦方法就是忽略或简化对所研究问题影响较小的一种运动,只分析主要的运动。
面向接口编程的优点远不止上面这种代码解耦的场景,在实际企业开发里,利用接口思想对已有代码进行灵活扩展也
特别常见。
改造过程中,我们只增加了代码,却并没有修改任何已有代码,就完成了代码扩展的任务,非常符合开闭原则!
#################################################################
CPU给时间片5毫秒
A用4.5结束
则cpu不会等剩下的0.5,自动提前结束掉A的时间片,切给下一个
#################################################################
栈 堆
±—+
|对象|
±—+
+----+
|对象|
+----+
6.3 问题
每次创建线程对象,都会生成一个tickets变量值是100,创建4次对象就生成了400张票了。不符合需求,怎么解决呢?能不能把tickets变量在每个对象间共享,就保证多少个对象都是卖这100张票。
解决方案: 用静态修饰
产生超卖,0 张 、-1张、-2张。
产生重卖,同一张票卖给多人。
多线程安全问题是如何出现的?常见情况是由于线程的随机性+访问延迟。
以后如何判断程序有没有线程安全问题?
在多线程程序中 + 有共享数据 + 多条语句操作共享数据
#########################################################################
同步:体现了排队的效果,同一时刻只能有一个线程独占资源,其他没有权利的线程排队
坏处就是效率会降低,不过保证了安全.
异步:体现了多线程抢占资源的效果,线程间互相不等待,互相抢占资源。
坏处就是有安全隐患,效率要高一些。
同步效果的使用有两个前提:
前提1:同步需要两个或者两个以上的线程(单线程无需考虑多线程安全问题)
前提2:多个线程间必须使用同一个锁(我上锁后其他人也能看到这个锁,
不然我的锁锁不住其他人,就没有了上锁的效果)
线程start时获得的是那一瞬间的[公共值]
打印的是那一瞬间的[公共值]-1
但实际反映到存储空间中,是实际的[公共值]-1
所以其他人
1.多线程中出现数据安全问题的原因:多线程程序+共享数据+多条语句操作共享数据
2.同步锁:想当于给容易出现问题的代码加了一把锁,包裹了所有可能出现数据安全问题的代码
*加锁之后,就有了同步(排队)的效果,但是加锁的话,需要考虑:
*锁的范围: 不能太大否则会一直排队,不能太小否则锁不住
解决数据安全问题:
1措施:添加同步代码块
注意:锁对象必须是同一个,必须唯一
注意:代码块的范围要合适
2.措施:增加了一个判断了一个判断,有票的时候再卖票
同步代码块:
synchronized(锁对象){
会出现安全隐患的所有代码;
}
同步代码块在同一时刻,同一资源只会被一个线程独享
//创建锁对象 Object o = new Object();
if(tickets>0){ } /*解决超卖的问题,有票时再卖/
try {Thread.sleep(10);} catch(){}//手动睡眠阻塞
out目录下的.class字节码文件与java文件里的类一一对应\
适合锁对象?
两种实现方式的比较
继承Thread类
优点: 编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this即可获得当前线程
缺点: 自定义的线程类已继承了Thread类,所以后续无法再继承其他的类
实现Runnable接口
优点: 自定义的线程类只是实现了Runnable接口或Callable接口,后续还可以继承其他类,在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码、还有数据分开(解耦),形成清晰的模型,较好地体现了面向对象的思想
缺点: 编程稍微复杂,如想访问当前线程,则需使用Thread.currentThread()方法
#########################################################################
常量池—有一个高效的效果
Bean池(对象池)---->spring中的一部分---->租用对象
多线程方案三
线程池----->
ExecutorService/Executors
ExecutorService:用来存储线程的池子,把新建线程/启动线程/关闭线程的任务都交给池来管理
execute(Runnable任务对象) 把任务丢到线程池
Executors 辅助创建线程池的工具类
newFixedThreadPool(int nThreads) 最多n个线程的线程池
newCachedThreadPool() 足够多的线程,使任务不必等待
newSingleThreadExecutor() 只有一个线程的线程池
######################################################################
+----------------------------------------+
| |
| |
| 进程/线程 结束 |
| |
| |
+----------------------------------------+
######################################################################
<反射>
反射就像一面镜子,它可以在运行时获取一个类的所有信息,
可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段、方法、构造器等部分。
JAVA-API的lang包下都是核心基础接口
反射需要用到的API
获取字节码对象
Class.forName(“类的全路径”);
类名.class
对象.getClass();
联想思路
看到三种核心方法
–>获取字节码对象
–>是反射
Class<?> XXX = 三句用来获取的方法();
声明字节码对象
######################################################################
PCB进程控制块:
OS系统为了管理进程设置的一个专门的数据结构。系统用它来记录进程的外部特征,描述进程的运动变化过程。
同时,系统可以利用PCB来控制和管理进程,所以说,PCB(进程控制块)是系统感知进程存在的唯一标志。
线程暂时存放从公共存储读来的数据自己的临时存储也在于此.
######################################################################