http://www.ibm.com/developerworks/cn/java/j-jtp06197.html 一文笔记
在java中,为了提高性能,线程一般把变量从内存中备份一个副本到寄存器。volatile 关键字意思是易失性,明确表示
一个变量是会被多线程访问的,每个线程在每次读取都要从内存读取原始副本的值,而不是缓存在寄存器中的值。每次修改
都是把值写回到内存中。
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。
synchronized锁提供了两种主要特性:
互斥(mutual exclusion) 和
可见性(visibility)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的。 否则,线程看到的共享变量可能是修改前的值或不一致的值,引发严重问题。
volatile能够实现上述可见性,因为线程每次都是读取原始版本的值,前一个线程的修改对后续线程来说是可见的。但volatile不能确保互斥。
volatile适用的原则:
- 对变量的写操作不依赖于当前值。
- 该变量没有包含在具有其他变量的不变式中。
所以volatile不能用作计数器,因为计数器的自增是一个读-增-写的过程,不是原子操作,在volatile不确保互斥的情况下,结果不准确。
不变式的意思是一个需要不变的规律,如起始要小于等于结束。上述2点简单来说:即变量真正独立于其他变量和自己以前的值 , 在这些
情况下可以使用
volatile
代替
synchronized
来简化代码。
volatile由于不阻塞线程,在性能一般比synchronized表现更好。
适用volatile的几个场景:
1、状态标志 比如标示服务启动或停止。
2、独立观察 定期 “发布” 观察结果供程序内部使用,
3、
结合使用 volatile 和 synchronized 实现 “开销较低的读-写锁”
@ThreadSafe
public class CheesyCounter {
private volatile int value;
// 使用volatile实现可见性,开销低
public int getValue() { return value; }
// 使用synchronized实现互斥
public synchronized int increment() {
return value++;
}
}
posted @
2011-04-08 16:28 liucs 阅读(363) |
评论 (0) |
编辑 收藏
本文是阅读《高性能网站建设指南》一书的笔记。该书作者是Yahoo!的
Steve Souders ,总结了yahoo!在web前端优化的最佳实践。
Web前端性能黄金法则:只有10%-20%的最终用户响应时间花在下载html文档上。其余时间花在了下载页面中所有的组件上。
页面组件包括:图片,javascript,css,flash等内容
Http请求响应
GET /home/**.js
HTTP 1.1
Host: www.taobao.com
User-Agent: Mozilla/**
Accept-Encoding:gzip,deflate ----》支持压缩
If-Modified-since:web,22 Feb** -----》判断是否采用浏览器缓存
Expires:web**** -----》明确声明失效时间,避免If-Modified-since条件请求的至少一次与服务器的交互
Connection: keep-alive ----》使用长连接
--------------------------------------------------------------------------------------------------------------------
HTTP 1.1 304 Not Modified ----》没修改
Content-Type: application/x-javascript
Last-Modified : web,22**
Content-Encoding:gzip
更详细的见http规范: http://www.w3.org/Protocols/rfc2616/rfc2616.html
1、减少HTTP请求
- 使用图片地图 一个图片上面关联多个URL,由点击的位置决定目标URL,目的在于建设图片数量
- CSS Sprites 讲多个图片合并成一幅图片,图片地图中的图片要连续,Css Sprites不需要
- 内联图片
- 合并脚本和样式表 网站首页平均应该使用6、7个脚本和1、2个样式表
2、使用外部JavaScript和CSS
单纯来说,内联比外联更快一些。
对于用户访问很少的页面,比如注册等,建议内联。
对于用户访问较多的页面,比如list或者商品详情页面等,建议外联,浏览器可以使用缓存的组件。
对于重用性较高的组件,使用外联
3、使用内容发布网络
CDN(Content Delivery Network)内容分发网络,让用户就近访问页面静态组件
4、减少DNS查找
通常浏览器查询一个给定的主机名的ip需要花费20-120毫秒。建议将页面组件放在至少2个,但不超过4个的主机名下。
5、添加Expires或者Cache-Control头
Expires和Cache-Control头都用于浏览器可以使用本地缓存直至制定的时间,web服务器如apache,lighttpd,nginx等都有相应模块可配置
6、精简JavaScript
精简代码,将所有不必要的注释和空白换行等移除。可以使用 JSMin(http://crockford.com/javascript/jsmin)进行精简。
7、压缩组件
Accept-Encoding头,一般只压缩脚本和样式表,图片不需要,因为图片通常都是压缩过的。Apache 2.x使用mod_deflate模块gzip压缩
8、避免重定向
重定向使得html文档到达前,页面不会呈现任何内容。所以要减少重定向
9、将样式表放在顶部
样式表放在底部,浏览器为了在样式表变化时不需要重绘页面会阻止内容自顶向下逐步呈现。将CSS放在顶部,有利于浏览器从上向下显示页面。
推荐使用<link rel="stylesheet" href="common.css">方式,而不是import方式,因为import方式会导致组件下载的无序性,破坏了放在顶部的初衷。
10、移除重复脚本
由于团队成员的长期维护,会遗留一定的重复脚本,需要定期清理
11、将脚本放在底部
浏览器遵从http规范并行的从每个主机名并行下载两个组件。这样可以有效提高下载的效率。但浏览器在下载脚本时时禁用并行下载的,因为脚本有可能修改页面内容。浏览器会阻塞确保页面恰当的布局。
12、配置ETag
13、避免CSS表达式
CSS表达式是实现的效果可以通过其他手段实现,并且风险更小。
14、使Ajax可缓存
Ajax只是实现了异步,避免页面的重新加载,但是不意味着即时。所有一个用户在操作后仍然要等待才能看到结果。一些缓存的原则也可以适用于ajax.
Ajax的POST要两步,而GET只需要一步。所以尽量采用get方式。GET 方式可以更快响应,但是可能会有被浏览器缓存的问题,一般都需要加个随机数来避免,POST 方式则不会。
15、Cookie
减少cookie中的信息,避免不重要的信息放在cookie中;对于图片或者静态服务器,使用cookie无关的域名,避免cookie的传输。
posted @
2011-04-08 10:59 liucs 阅读(293) |
评论 (0) |
编辑 收藏
低耦合、高内聚
OOP设计原则主要提供了一个方向,使得我们的程序设计得更加合理,从而获得更好的可扩展性、可维护性。主要包括以下几个原则:
1、
OCP(Open-Closed Principle) 开放封闭原则。
对扩展开放,对修改关闭。即在不修改原有程序源码的情况下对其进行扩展。实现开闭原则的关键就在于“抽象”。
“作为系统设计的抽象层,要预见所有可能的扩展,从而使得在任何扩展情况下,系统的抽象底层不需修改;同时,由于可以从抽象底层导出一个或多个新的具体实
现,可以改变系统的行为,因此系统设计对扩展是开放的。 ” 这个原则是OOP的基石,其他原则主要来实现本原则。
2、
SRP (Simple Responsibility Pinciple)单一职责原则。
一个类一般应该设计成只有一个职责,如果设计成具备很多职责,那么任何一个职责的改变都会引起这个类的修改,相关引用该类的代码也可能受到影响。不同的职责或功能应该由不同的类来实现,这样可以很好的控制变化带来的影响粒度。
3、
DIP (Dependence Inversion Principle)依赖倒转原则。
抽象不应该依赖于实现细节,实现细节应该依赖于抽象;高层不应该依赖于底层,都应该依赖于抽象。针对接口编程: 应该用接口或者抽象类声明变量、方法参数、方法返回类型等。
4、
LSP (Liskov Substitution Principle)里氏代换原则。
子类型完全可以替换父类型,而不需要任何修改,并且获得期望的结果。
5、
ISP (Interface Segregation Principle)接口隔离原则。
客户端不应该可以访问不需要的方法,这些不需要的方法是一种有害的耦合性。
所以应该设计多个专门接口而不是单个复杂的接口,客户端仅依赖最小的接口类型。
6、
LoD (Law of Demeter)迪米特法则。
即最少知识原则。一个对象应当对其他对象有尽可能少的了解。只和最直接的类交互,对第三方可以通过转达交互,从而减少对象间的耦合性。
7、
CARP (Composite/Aggregate Reuse Principle)合成/聚合复用原则。
多聚合、少继承,实现复用性。聚合的复用是一种封闭性的复用,被复用者对复用者隐藏了自身细节,而继承是一种开放性的复用,子类可以获取父类型相关的细节,破坏了封闭性。
posted @
2011-03-31 14:07 liucs 阅读(386) |
评论 (0) |
编辑 收藏
Java Reflection 是一种
内省机制,帮助程序在
运行时对自身及软件环境进行检查,并根据检查得到的程序结构,改变自身的部分行为。
核心类为
java.lang.Class 类,抽象了程序的元数据,每一个类的元数据就是一个Class对象实例。这个Class实例是一个静态实例,对应类的每一个实例都会关联这个静态实例。通过Class类可以查询该类的方法、字段、接口、构造器等一系列信息。详见下面。
对象回去自身对应的Class实例是通过继承自Object类的getClass()方法;
对于基本类型,每一种也有一个名为class的静态实例,如int.class double.class boolean.class;
对于数组类型,也有Object[].class, 注意 int[][].class==int[].class
判断对象类型的接口:
String getName() 获得类全名
Class getComponentType() 如果对象是数组,返回数据中元素的类类型
boolean isArray()
boolean isInterface()
boolean isPrimitive()
boolean isAnnotation()
###########################################################################################################
接口
java.lang.Class中定义的检查接口的接口:
Class[] getInterfaces()
Class getSuperClass() 直系父类 ,对于Object、接口、void关键字、基本类型,返回null
boolean isAssignableFrom(Class cls) 该类是参数的类型或参数的父类型
boolean isInstance(Object obj) 该类是参数的实例或者参数的子类实例
Class类和Object类存在比较纠结的关系
Class.class.isIntance(Class.class) == true Class类的class实例是Class本身的实例
Class.class.isInstance(Object.class) == true
Object.class.isAssignableFrom(Class.class) == true
Object.class.isIntance(Class.class) == true
###########################################################################################################
java.lang.reflect部分类图
###########################################################################################################
java.lang.reflect.Constructor
java.lang.Class中相关方法
Constructor getConstructor(Class[] parameterTypes)
Constructor getDeclaredConstructor(Class[]parameterTypes)
Constructor[] getConstructors()
Constructor[] getDeclaredConstructors()
java.lang.reflect.Constructor
Class getDeclaredClass()
Class[] getExceptionTypes()
int getModifiers()
String getName()
Class[] getParameterTypes()
Object newInstance(Object[] initArgs) 创建实例
对于数组,使用 java.lang.reflect.Array.newInstance(String.class,5)形式创建实例
###########################################################################################################
java.lang.reflect.Method
java.lang.Class类中定义了如下接口查询一个类所具有的方法。
Method getMethod(String name,Class[]parameterTypes)
Method[] getMethods()
上述2个接口查询继承获得和自身声明的方法
Method getDeclaredMethod(String name,Class[]parameterTypes)
Method[] getDeclaredMethods()
上述2个接口查询自身声明的方法
java.lang.reflect.Method类定义的方法
Class getDeclaringClass() 声明该方法的类实例
Class[] getExceptionTypes() 方法的异常类型
int getModifiers() 方法的可见性
String getName() 方法名
Class[] getParameterTypes() 方法参数类型
Class getReturnType() 方法返回类型
Object invoke(Object obj,Object[]args) 反射调用一个对象上面的该方法
###########################################################################################################
java.lang.reflect.Field
java.lang.Class类中关于Field的相关方法:
Field getField(String name)
Field[] getFields()
Field getDeclaredField(String name)
Field[] getDeclaredFields()
java.lang.relect.Field中主要方法
Class getType() 返回字段的Class
Class getDeclaringClass() 返回什么该字段的Class
String getName()
int getModifiers()
Object get(Object obj) 返回obj该字段的值
boolean getBoolean(Object obj)
void set(Object obj,Object value) 设置obj该字段的值
void setBoolean(Object obj,boolean value)
###########################################################################################################
java.lang.reflect.Modifier 字段或者方法的访问性
static boolean isPublic(int mod)
static boolean isPrivate(int mod)
共包括以下:
public static native volatile protected transient
abstract synchronized strictfp private final
###########################################################################################################
动态加载
Class cls = Class.forName(String className);
Object obj = cls.newInstance();
动态加载机制使得可以避开编译器类范围的限制,常见场景是jdbc驱动。动态加载机制也是通过ClassLoader实现。
通过动态加载机制的类名并不是一般意义的类名,而是:
1、基本类型,首字母大写,如 int -> I
2、引用类型,L+全类名,如 Ljava.lang.String
3、数组类型,[+***, 如[I, [Ljava.lang.String , [[I, [[Ljava.lang.String
注意:基本类型,不能通过Class.forName()加载,会抛出异常
posted @
2011-03-31 14:06 liucs 阅读(319) |
评论 (0) |
编辑 收藏
Java在方法参数传递时:
1、对于基本类型,传递值
2、对于对象类型,传递对象引用
需要注意的是:对于上述两种传递类型,在传递时都是拷贝传递,即值传递时拷贝出一个新值,引用
传递时拷贝出一个新的拷贝。
有时候也说Java只有值传递,意思是对于引用类型,传递引用的值。一个概念,不用纠缠。
在内存中对象类型可以看做两块,一块是对象的引用,一块是数据区。引用块里面保存了数据区的地址。
看如下示例代码:
1 public class Test {
2
3 public static void main(String[] args) {
4 // 值传递
5 int i = 1;
6 addInt1(i);
7 System.out.println(i);// 输出1
8 addInt2(i);
9 System.out.println(i);// 输出1
10
11 // 引用传递实例1
12 String str = "123";
13 modifyStr1(str);
14 System.out.println(str);// 输出123
15
16 // 引用传递实例2
17 StringBuilder stringBuilder = new StringBuilder("123");
18 modifyStringBuilder(stringBuilder);
19 System.out.println(stringBuilder.toString());// 输出123456
20 }
21
22 // 拷贝了新的值,原值不变
23 public static void addInt1(int i) {
24 i = 2;
25 }
26
27 // 拷贝了新的值,原值不变
28 public static void addInt2(int i) {
29 i++;
30 }
31
32 // 新的拷贝引用指向了一块新数据区,原拷贝仍然指向原数据区
33 public static void modifyStr1(String str) {
34 str = "456";
35 }
36
37 // 新的拷贝引用仍然指向原数据区,但修改了原数据区的内容
38 public static void modifyStringBuilder(StringBuilder str) {
39 str.append("456");
40 }
41
42 }
posted @
2011-03-31 14:05 liucs 阅读(295) |
评论 (0) |
编辑 收藏