Volatile
Java语言提供了一种稍弱的同步机制,即valatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为valtile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。总之,volatile变量是一种比sychronized关键字更轻量级的同步机制。
仅当volatile变量能简化代码的实现以及对同步策略的验证时,才应该使用它们。volatile变量的正确使用方式包括:确保它们自身状态的可见性,确保它们所引用对象的状态的可见性,以及标识一些重要的程序生命周期事件的发生。
volatile变量通常用做某个操作完成、发生中断或者状态的标志。
volatile boolean asleep;
...
while (!asleep) {
...
}
普通变量和volatile变量的区别是:volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。因此,可以说volatile保证了多线程操作时变量的可见性,而普通变量则不同保证这一点。
Java内存模型
Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性这3个特征来建立的。
原子性
可见性
可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。
除了volatile之外,Java还有两个关键字能实现可见性,即synchronized和final。同步块的可见性是由“对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store、write操作)”这条规则获得的,而final关键字可见性是指:被final修改的字段在构造器中一旦初始化完成,并且构造器没有把“this”的引用传递出去,那在其他线程中就能够看见final字段的值。
有序性
如果在本线程内观察,所有的操作都是有序的;如果在一个线程中观察另一个线程,所有的操作都是无序的。前半句是指“线程内表现为串行的语义”,后半句是指“指令重排序”现象和“工作内存与主内存同步延迟”现象。
Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile关键字本身就包含了禁止指令重排序的语义,而synchronized则是由“一个变量在同一时刻只允许一条线程对其进行lock操作”这条规则获得的,这条规则决定了持有同一个锁的两个同步块只能串行的进入。
先行发生原则
Java语言中有一个“先行发生”(happens-before)的原则,这个原则非常重要,它是判断数据是否存在竞争、线程是否安全的主要依据,依靠这个原则,我们可以通过几条规则一揽子地解决并发环境下两个操作之间是否可能存在冲突的所有问题。
先行发生是Java内存模型中定义的两项操作之间的偏序关系,如果说操作A先行发生于操作B,其实就是说发生操作B之前,操作A发生的影响能被操作B观察到,“影响”包括修改了内存中共享变量的值、发送了消息、调用了方法等。
Session和Cookie
Session合Cookie都是回话(Session)跟踪技术。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。但是Session的实现依赖于Cookie,SessionId(session的唯一标识需要存放在客户端)。
- cookie数据存放在客户的浏览器上,session数据放在服务器上
- cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
所以个人建议:将登陆信息等重要信息存放为session;其他信息如果需要保留,可以放在cookie中,比如购物车。
事务
事务是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。
- 原子性:表示事务内操作不可分割,要么都成功,要么都失败
- 一致性:要么都成功,要么都失败,后面的失败了要对前面的操作进行回滚
- 隔离性:一个事务开始后,不么受其他事务干扰
- 持久性:表示事务开始了就不能终止
Spring总结
控制谁?当然是IoC 容器控制了对象;
控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;
哪些方面反转了?依赖对象的获取被反转了。
- 谁依赖于谁:当然是应用程序依赖于IoC容器;
- 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
- 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
- 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊,所以又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
<context:component-scan base-package="com.yonyou.yls"/>在xml配置了这个标签后,spring可以自动扫描base-package下面或者子包下面的java文件,如果扫描到有@Component @Controller @Service @Repository等这些注解的类,则把这些类注册为bean。
Use-dafault-filters=”false”的情况下:<context:exclude-filter>指定的不扫描,<context:include-filter>指定的扫描
<mvc:annotation-driven/>是告知Spring,我们启用注解驱动。然后Spring会自动为我们注册上面说到的几个Bean到工厂中,来处理我们的请求。
配置Spring和Spring Mvc,主要有:
1.在web.xml中配置好Spring相关Listener/Filter/Servlet,并指明Spring和Spring Mvc的配置文件,当然,也可以不指定,放在classpath下就行,严谨一点还是写出来为好。
2.配置applicationContext.xml,这个是给Spring用的,名字随意,只要在web.xml指定就行。
3.配置 spring-servlet.xml,这个是给Spring Mvc用的,名字随意,只要在web.xml指定就行。
transient
java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。像银行卡、密码等等这些数据。这个需要根据业务情况了。被transient修饰后不会被序列化。
网友评论