凉衫薄

人生哪能多如意,万事只求半称心。
最新文章
nginx配置结构 ... #全局块 events { #events块 ... } http #http块 { ... #http全局块 server #server块 { ... #server全局块 location [PATTERN] #location块 { ... } location [PATTERN] { ... } } server { ... } ... #http全局块 } root和alias的区别 root的处理结果是:root路径+location路径 alias的处理结果是:使用alias路径替换location路径 alias是一个目录别名的定义,root则是最上层目录的定义。 还有一个重要的区别是alias后面必须要用“/”结束,否则会找不到文件的,而root则可有可无。 root举例 location ^~ /prefix/ { root /www/root/html/; } 当请求的URI是/prefix/a.html时,服务器返回/www/root/html/prefix/a.html。 alias举例 location ^~ /prefix/ { alias /www/root/html/; } 当请求的URI是/prefix/a.html时,服务器返回/www/root/html/a.html。
一、引言 如果说盗梦空间的剧情是递归,那么恐怖游轮绝对是不同代码分支中的循环以及多进程的同步过程。 二、工程结构及代码逻辑 1、该剧情有master和dev两个代码分支 2、dev分支的代码逻辑只包含邮轮上剧情,非死循环(包括邮轮上的三个‘小循环’,其实是顺序结构,分别表示dev分支中女主的三个时期D1、D2、D3),这是一个多进程的程序,假设当前进程为dev分支的进程1,我们从当前进程的角度来描述这三个时期: D1时期:女主从帆船上刚踏进邮轮 D2时期:女主看见master分支进程1的女主踏进邮轮(此时相对于master分支进程1中的女主是M1时期) D3时期:女主看见dev分支进程2的女主踏进邮轮(此时相对于dev分支进程2中的女主是D1时期),并最终被dev分支进程2的女主杀死 伪代码先这样表示着: //轮船剧情 public void liner(){ D1(); D2(); D3(); } 3、master分支的逻辑包括岸上剧情和邮轮剧情,且总体是死循环(包括岸上剧情的顺序结构和邮轮上有三个‘小循环’,其实也是顺序结构,分别表示master分支中女主在船上的三个时期M1,M2,M3,岸上剧情表示为M0),master分支同样是多进程,假设当前进程为master分支的进程1,我们从当前进程的角度来描述这四个时期: M0时期:女主的岸上剧情 M1时期:女主从帆船上刚踏进邮轮 M2时期:女主看见dev分支进程1的女主踏进邮轮(此时相对于dev分支进程1中的女主是D1时期) M3时期:女主看见master分支进程2的女主踏进邮轮(此时相对于master分支进程2中的女主是M1时期),并最终被master分支进程2中的女主推下海,死循环进入岸上剧情的M0时期 用伪代码先这样表示着: //岸上剧情 void shore(){ } //邮轮剧情 void liner(){ M1(); M2(); M3(); } //总剧情 while(true){ shore(); liner(); } 三、如何运行 4、这是一个多进程的程序,难点就在进程的同步过程 5、首先master分支代码起多个进程(最少两个,因为邮轮的剧情进行M1时期的女主可以遇到M3时期的女主,她们同属于master分支的不同进程,master分支的进程可以理解为守护进程,是死循环会一直留在系统当中,参与与dev分支进程的同步) 6、其次dev分支代码起多个进程(dev分支的代码是非死循环的,在dev分支的邮轮剧情中,D3时期的女主会被另一个进程中正在经历D1时期的女主杀死从而结束进程,所以dev分支是需要不断的有新进程启动加入才能维持这个同步过程的) 四、进程的同步过程 7、需要同步的代码块只发生在邮轮上,且同一时刻同步过程中多个进程之间的状态只能有以下两种情况 情况一:M1 D2 M3 情况二:D1 M2 D3 引用B站某up主的视频截图就是如下所示(斜对角就是一个进程在邮轮剧情上的生命周期): 8、M3结束后,master分支中的女主又开始岸上剧情,以此循环下去。D3结束,意味着dev分支中的女主被杀死了,该进程的生命周期就结束了,为了维持这个同步过程,需要不断地再启动一个dev分支的进程,并加入到同步当中,换句话也就是说,master分支中正处于M2时期的女主又看到dev分支中的女主踏上邮轮了。啊啊啊!!!烧脑啊!!! 五、以Java多线程同步方式继续完善伪代码 dev分支: //D1时期 void D1(){ //获取时期1的锁,只允许一个进程进入时期1 synchonized(period1){ //判断是否可以进入D1时期,否则等待 while(!condition){ period1.wait(); } //TODO 开始D1时期剧情 //唤醒其他等待进入时期1的进程 period1.notifyAll(); } } //D2时期 void D2(){ //获取时期2的锁,只允许一个进程进入时期2 synchonized(period2){ //判断是否可以进入D2时期,否则等待 while(!condition){ period2.wait(); } //TODO 开始D2时期剧情 //唤醒其他等待进入时期2的进程 period2.notifyAll(); } } //D3时期 void D3(){ //获取时期3的锁,只允许一个进程进入时期3 synchonized(period3){ //判断是否可以进入D3时期,否则等待 while(!condition){ period3.wait(); } //TODO 开始D3时期剧情 //唤醒其他等待进入时期3的进程 period3.notifyAll(); } } //轮船剧情 void liner(){ D1(); D2(); D3(); } master分支: //岸上剧情 void shore(){ } //M1时期 void M1(){ //获取时期1的锁,只允许一个进程进入时期1 synchonized(period1){ //判断是否可以进入M1时期,否则等待 while(!condition){ period1.wait(); } //TODO 开始M1时期剧情 //唤醒其他等待进入时期1的进程 period1.notifyAll(); } } //M2时期 void M2(){ //获取时期2的锁,只允许一个进程进入时期2 synchonized(period2){ //判断是否可以进入M2时期,否则等待 while(!condition){ period2.wait(); } //TODO 开始M2时期剧情 //唤醒其他等待进入时期2的进程 period2.notifyAll(); } } //M3时期 void M3(){ //获取时期3的锁,只允许一个进程进入时期3 synchonized(period3){ //判断是否可以进入M3时期,否则等待 while(!condition){ period3.wait(); } //TODO 开始D3时期剧情 //唤醒其他等待进入时期3的进程 period3.notifyAll(); } } //邮轮剧情 void liner(){ M1(); M2(); M3(); } //总剧情 while(true){ shore(); liner(); }
事务四种特性 特性 说明 原子性 强调事务的不可分割 一致性 事务执行前后数据完整性保持一致 隔离性 一个事物执行的过程中,不应该受到其他事务的干扰 持久性 事务一旦结束,数据就持久到数据库 安全性问题 问题 说明 脏读 读取其他事务未提交的数据 不可重复读 一个事务前后多次读取其他事务已提交update的数据 幻读 一个事务前后多次读取另一个事务已提交的insert或delete数据,导致数据总量不一致 事务隔离级别 隔离级别 说明 default 使用数据库的默认隔离级别 未提交读 脏读,不可重复读,虚幻读都有可能发生 已提交读 避免脏读,不可重复读,虚幻读可能发生 可重复读 避免脏读和不可重复读,虚幻读可能发生 串行化 避免以上所有问题 Mysql默认级别 可重复读 Oracle默认级别 已提交读 事务传播行为 事务传播行为类型 说明 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。 PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
Bean生命周期 1、实例化对象(构造函数或工厂函数) 2、设置对象属性 3、Aware相关接口(BeanNameAware,BeanFactoryAware) 4、BeanPostProcessor接口中的postProcessBeforeInitialization()方法 5、@PostConstruct注解方法 6、InitialingBean接口中的afterPropertiesSet()方法 7、xml配置中的init-method方法 8、BeanPostProcessor接口中的postProcessAfterInitialization()方法 9、@PreDestroy注解方法 10、DisposableBean接口中的destroy()方法 11、xml配置中的destroy-method方法
一、概念 将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。 二、优缺点 优点:客户端不必知道产品内部组成的细节,缺点:产品的组成部分必须相同 三、与工厂模式的区别 建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。 四、例子 电脑类 public class Computer{ private String cpu; private String gpu; private String memory; private String disk; public void setCpu(String cpu){ this.cpu = cpu; } public void setGpu(String gpu){ this.gpu = gpu; } public void setMemory(String memory){ this.memory = memory; } public void setDisk(String disk){ this.disk = disk; } } 建造者抽象类 public Abstract class ComputerBuilder{ protected abstract void buildCpu(Computer computer); protected abstract void buildGpu(Computer computer); protected abstract void buildMemory(Computer computer); protected abstract void buildDisk(Computer computer); public Computer builder(){ Computer computer = new Computer(); buildCpu(computer); buildGpu(computer); buildMemory(computer); buildDisk(computer); return computer; } } 建造者实现类 public class AlienwareBuilder extends ComputerBuilder{ protected void buildCpu(Computer computer){ computer.setCpu("i9"); } protected void buildGpu(Computer computer){ computer.setGpu("GTX2080"); } protected void buildMemory(Computer computer){ computer.setMemory("32G"); } protected void buildDisk(Computer computer){ computer.setDisk("1T+512G"); } }