进程是操作系统层面的,去获取一个个CPU时间片
线程是应用层面的 一般一个进程会有多个线程
线程安全问题其实就是共享变量的问题。我们知道多线程情况下,可能要有多个线程去同时访问某个变量,这样可能回导致数据的脏读和其他问题 导致后续的处理也出现问题 就是线程安全
线程的状态:
1.创建
2.就绪
3.运行
4.通过sleep或者wait 就出现了线程阻塞
sleep并不让出资源锁 但是wait回让出
5.线程销毁
三种方法
1.集成thread
2.实现runnable接口
3.集成Callable接口 这个接口实现类可以通过FutureTask 对象获取到线程的返回值。
当一个线程调用 一个共享变量的 wai t()方法时, 该调用线程会被阻塞挂起, 直到发生
下面几件事情之一才返回 :
(1)其他线程调用了该共享对象的 notify()或者 notifyAll () 方法 ;
(2)其他线程调用了该线程 的 int errupt () 方法 , 该线程抛出 InterruptedExce ption 异常返回。
notify相当于一个通知,通知那些等待中的资源线程 但是必须当前线程释放资源锁,才能真正的跳回到之前的那个被阻塞的线程中
很明显这俩是用在共享对象上的 不是线程专有的
sleep 就是很简单的休眠多少时间,过了时间就会启动 锁什么的都还在的
yield 好像是时间片 让出当前时间片吧 重新竞争时间片
join就是字面意思 一个线程加入到另外一个线程中 ,想象一个线程栈 ,必须要 你这个加入进去的执行完 才能重新跳到当前线程
还是和前面的notifyall 一样的道理 不是notyfyall 了就回全部返回之前的线程,而是要获得资源锁 才能调回去
但是有一点区别在于
如果之前有两个线程之前都获得了锁 然后有都被wait了 然后某个线程执行了noty 只有其中第一个执行的线程回返回,而且 由于执行的线程没有notify 所以回导致线程一直等待。
而如果用了all 全部都会被唤醒
线程池 :可以用Executors 创建4个线程
1.newCachedThreadPool :可缓存线程池,先查看池中有没有以前建立的线程,如果有,就直接使用。如果没有,就建一个新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务
2.newScheduledThreadPool: 一个定长线程池,支持定时及周期性任务执行
3.newFixedThreadPool:创建一个可重用固定个数的线程池,以共享的无界队列方式来运行这些线程
4.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
CPU 物理核心
逻辑核心 -CPU可以执行多少线程
竞争条件: 多线程种出现的结果和期望不同
临界区:产生竞争条件的代码区 叫临界区
1.乐观锁CAS Compare and set (swap)
当你要更新一个内存地址的值时 需要告知我过去的值和想要更新的值 如果不对 会一直循环直到比较相同之后在修改 他和直接用lock不同的地方在于 如果使用了cas 进入了循环比较过程 同时被interrupt打断了
其他线程是可以拿到内存中最新的值进入比较的,但是如果是lock的话别的线程就不能动了
多线程的内存模型是这样的
基于一个共享变量,每个线程会复制内容到本地工作区间,然后再本地的工作空间里面操作数据
但是这样的问题就出现了 当返回数据的时候出现数据不一致 或者数据缺失 这就需要用volitate 来实现内存可见了
那么volitate是如何实现的呢
volatile写的内存语义:当写线程写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。
volatile读的内存语义:当读线程读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将从主内存读取共享变量。
某些时候volitate和synchronized作用相同,但是v只是线程可见,而S采用了悲观锁,别的线程直接无法访问 整个线程切换的时间花费会大很多
volatile不保证原子性 如果写入的依赖与当前值,比如说a++什么的 会导致volatile失效 必须用sy加锁 而如果加了锁,那么久没必要vo了
ThreadLocal 第一的线程本地存储,实际上是所谓共享变量,无非这个和线程相关的共享变量在底层通过一个人ThreadLocalMap /也就是类似hashmap 进行了存储,而 当线程调用时,只能通过键值对去调用本线程存储的变量信息
数据库事务分为:
1.读未提交 read uncommit
2.读已提交 read commit
3. Repeatable read (mysql 默认的事务)
4.串行化
Innodb Myisam
主外键 支持 不支持
事务 支持 不支持
锁 行锁 表锁
缓存 都缓存 对内存要求搞 只缓存索引 不缓存具体数据
表空间 大 小
关注点 事务 性能
percona xtrsdb 提升了高并发下的性能
悲观锁 :
实际上就是将一个个数据进行排序
在数据结构中我们知道要用二叉查找树的结构能够更好的更有效率额查找数据
而B树就是借鉴了这种方式 不过他的一个节点有很多个值,同时每个索引差不多就是mysql 在磁盘上存的页 他查找的时候
B+树的所有索引只放在叶子节点上,
从左往右要依次的处理
这种以主键作为 B+ 树索引的键值而构建的 B+ 树索引,我们称之为聚集索引。
覆盖索引是指有的索引会被覆盖掉 比如说
第一范式: 保证主键唯一 但是还是与传递依赖和部分函数依赖
第二范式:部分函数依赖
第三范式:存在非主属性对于码的传递函数依赖
通过mysql 配置 利用log实现数据同步
高性能
因为我们知道读取mysql或者别的数据库,实质上还是从硬盘去读取。我们知道操作系统的读写方式,需要数据从磁盘中替换到内存区,这个过程是相对比较慢的,但是我们马上第二次去取会发现很快,就是因为操作系统把这些数据存到了他自己的缓存中,但是这个缓存是有限的,一段时间可能就没了 比如重启一下服务啊什么的 所以提出一个用redis这样一个可持久化的缓存中间件去保存 将该用户访问的数据存在数缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
高并发:
这个更好理解了 首先高性能就能加快处理这些并发请求 ,另外用了redis处理一部分请求也可以大大增加数据库的性能
redis 可以持久化 就是数据存到磁盘
memcached 宕机就啥也没有了
1 Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
2 Redis支持数据的备份,即master-slave模式的数据备份。
3 Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
reids常用数据结构
4、定期删除、惰性删除
5、内存淘汰机制
6、持久化机制
7、缓存雪崩、缓存穿透、缓存击穿
看我的博客
1.spring中的5个注解
controller层:restcontroller controller ResponseBody RequestMapping Autowired
service : service
配置层 :Configuration
2.spring组件
3.ioc和aop
所谓的ioc 无非就是一种控制反转的思想,不仅仅在spring中,工厂模式都有这样的思想,无非ioc是通过xml或者注解等创建对象,让spring在启动时,容器就加载了所需要的对象
举个例子,很多的配置类加上了config其实也是一个对象 在实际项目中,加入了阿里的连接池就必须要配置mysql的配置类,不然就是找不到bean对象。
aop的话就是面向切面。简单的理解就是在执行 某些代码前 或者代码后 跳到另外一套独立的逻辑,比如说做简单的权限过滤的时候,就可以用这个,在用户操作或者做别的之前,过滤一遍。
还有swagger验证的白名单,也是用到了AOP的
实质上就是用了动态代理 增强方法,让他可以在某些方法之前执行或者之后执行
4.springmvc 流程
1.用户发起请求到dispathcerServlet
2.dis去匹配查找对应的handler ,handlerMapping(处理器映射) 匹配到对应的handler后就回返回
3.dis通过这个handler 去处理器适配器中找对应的处理器,实质就是我们mvc中的controller
4.controller处理得到一个modelandvirw 返回给前端控制器dis
5。dis得到之后就会去视图解析器解析 返回一个view
6 最后返回jsp 是一个经过渲染 数据填充的视图