最近项目开发中,在代码检视中发现不少的问题,可归为JAVA的基础问题。看来,真的是应了那句,入门容易出师难。
本文不打算详细介绍 synchronized 关键字的详细解释,只就其中几个自己遇到的常见问题,做下论述。
现将自己对 JAVA synchronized 关键字的理解,阐述一下,如有雷同,纯属巧合。
一、Synchronized 与对象,锁的关系
很早之前,看到过一篇很不错的文章(http://buaawhl.iteye.com/blog/164905),可以说,自己对多线程编程的入门,就是直接在此受益。以致后来也慢慢进入了这个多线程的多姿多彩的世界。
Synchronized 同步关键字。其用法网络上面很多文章已经讲到。这次要说的是它和对象,锁有什么关系呢?其实,在我们的使用过程中,是否意思到这一点呢,使用JVM线程监控工具,看下,你会发现,使用Synchronized关键字的地方,如果程序还在其中执行,你会看到 - locked <0x24100198> 类似这样的信息,那类似 0x24100198 是什么呢?google一把看看。那篇文章有这样一句话:
想要继续深入了解synchronzied(同步锁)的实际运行机制。Java虚拟机规范中(你可以在google用“JVM Spec”等关键字进行搜索),有对synchronized关键字的详细解释。synchronized会编译成 monitor enter, … monitor exit之类的指令对。Monitor就是实际上的同步锁。每一个Object Reference在概念上都对应一个monitor。
看来,应该先有对象的,其次是有个叫 Object Reference 的。至于 文中所说概念上 每个 Object Reference 都对应一个 monitor。这句话,不太敢苟同,一方面是每个实际对象,可能会有多个 Reference,难道同一个对象的多个 Reference 就需要对应多个 monitor 么? 更为重要的一方面,就是对更为底层的实现不甚了解。我现在的想法应该是,monitor是对应实际对象的。
说到这里,我们的脑海里一定要想着,如果使用 Synchronized,一定是关联到某个实际对象的(JAVA 声称,一切都是对象。
public class Object 类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。)注意这个地方说的实际对象,
与我们常说的类与对象中的这个对象的区别。再明白点,就是使用 Synchronized,要么是和某个Class 关联,要么和某个Class的对象关联的。
那么,就是说,基本数据类型比如这样的写法 int i = 100;synchronized(i){...};这样,编译器就不允许我们这样做。所以,再次强调的是 使用 synchronized 时,关联的是对象,这个对象有一把锁。(这个锁也是个对象,只是给我们隐藏了。)
二、Synchronized与String,Integer 等对象使用上
2.1 与String使用
关于String,这个需要花费很大的篇幅如果需要彻底说明白它。包括多年编程的人员,至今遇到这样或那样的面试题感到茫然。这里推荐一篇文章,http://www.iteye.com/topic/209904。但与synchronized关键字有什么关系呢?
Recall section 3.10.5 of the Java Language Spec 2.0:
It says among other things:
"Literal strings within different classes in different packages likewise represent references to the same String object."
For the code above this means that any number of foreign classes can contain the same literal which translates to the same object, hence creating potential dead-lock situations!
This is also true for Strings for which you call the intern() method!
具体看下: http://www.javalobby.org/java/forums/t96352.html
2.2 与Integer 和Long ,Double 等数值型对象
其实这个问题,是上一个问题的另一面,如果我们业务上,如果 Synchronized 关联的对象是这些数值类型,注意的地方是,比如定义 Integer i = 100;synchronized(i){...}
类似这样的调用,如果除去业务含义,真的有数值一样的对象存在;这样的使用时也是存在风险的。因为可能多个貌似不同的引用却实际上是同一个对象。Integer i = 100;这样的写法,后台编译成了 Integer i = Integer.valueOf(100);这样的调用,看看源码发生了什么吧,你就知道我在说什么了。
三、Synchronized遇见了 null 对象
刚才说了,synchronized 是关联对象的,这个问题就是 null 是对象么?参考http://lavasoft.blog.51cto.com/62575/79243。
只所以说到这个问题,因为常常发现有的人就是这样的使用。比如:List<Object> objList = XXXXX;//(外部系统,或是参数传递而来的)
接下来就有这样的代码:
synchronized(objList) {
if(objList == null){
objList = new ArrayList<Object>();
}
....................//一系列处理
}
再此,我只想说,顶你的肺,synchronized,遇到null,直接抛空指针异常了。还搞个鬼啊。
四、小结
说了,这么多,在使用 synchronized 这个关键字的过程中,脑子里首先想到的一点就是,这个一定是和对象关联的。第二点,就是这个对象,你要注意的是否符合你的需求。就是要使用正确的对象。当然不是null。
另外,多补充一句,如果想深入理解多线程编程:首先要里面两类基本模型。1.同步模型 2。信号量模型。其他衍生出来的设计,实现,等等,都是在这两类模型上做文章。