简单的问题通常都不好回答,尤其在面试的时候,应对类似非常基础的问题时,应聘者通常很难抓住面试官提问的心理,假如回答稍有偏差,可能就会影响面试官对应聘者的印象,给面试的结果带来不确定性。
说起来Java的同步在使用上是非常简单的,具体而言可以概括为,同步方法和同步块。方法前加上synchronized,这个方法即是同步的,而使用synchronized(obj)和一对大括号包围住的代码块,则是同步块。听起来比较复杂、拗口,可能不好理解,那么见如下样例代码。
public class Test {
private static final Object lock = new Object();
private final Object lock2 = new Object();
public synchronized void testA() {
// some code
}
public static synchronized void testB() {
// some code
}
public void testC() {
synchronized (this) {
// some code
}
}
public void testD() {
synchronized (lock) {
// some code
}
}
public void testE() {
for (int i = 0; i < 10; ++i) {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock2) {
// some code
}
}
}).start();
}
}
}
样例中,testB是类的成员方法,testB是类的静态方法,testC、testD和testE演示了同步块的使用方法,区别在于testC的同步对象是对象自身,testD使用了类的静态成员,testE使用了对象的成员。
上述的几个样例最终都可以完成同步的需求,区别在于同步的范围和加锁的对象不同。根据实地编码的经验看,在不考虑死锁的情况下,同步的范围对代码运行效率有影响,在业务允许时一般范围越小越好。根据《深入浅出JVM》一书的介绍,Java语言中同步块的加锁对象有两类,类对象和类的实例对象。根据这两点可以对上述样例中的各个方法做个点评。
方法testA,类的成员方法,当某个实例在多线程中同时访问这个方法时,在某一具体时刻,只能有一个线程进入到这个方法内部,其它线程只能等待;由于testA在调用时需要绑定具体的对象实例,因而只有在多线程中访问同一个实例对象时,才会达到同步的效果;如果实例存在多个同步方法,当多个同步方法在多个线程中被调用时,由于锁定的对象是同一个,因而同一时刻,只有一个线程可以执行这个实例的某个方法,其它线程需要等待。
方法testB,类的静态方法,当在多个线程中同时调用这个方法时,在某一具体时刻,只能有一个线程进入到这个方法内部,其它线程只能等待;调用静态方法不需要绑定实例,因而与实例的同步方法调用不会出现同步现象。
方法testC,演示了代码块的使用方法,这里使用对象自身作为锁定对象,当这个对象在多个线程中共享访问这个同步块时会出现同步;同步范围变小,由整个方法缩小到了代码块内部。
方法testD,演示了使用类的静态对象作为锁定对象,当这个类的对象在多线程条件下访问testD方法内的同步块时,由于需要对类的静态对象加锁,这样即便不是相同的对象,仍然会达到同步的效果。
方法testE,最终达到的效果和方法testC相同,这种写法的优点是可以定义多个锁对象,这样不同的业务可以使用不同的加锁对象,在某种程度上可以更精确的控制加锁的范围,提高代码运行的效率。
总结一下,前面的描述比较罗嗦,知识点如下:
1、同步方法,包括类的静态方法和实例方法
2、同步代码块
3、构造函数不可以加同步关键字,这是一个语法错误。
4、子类覆盖父类的同步函数时,需要显式在覆盖后的方法前增加synchronized关键字,否则方法会失去同步的属性。
网上的资料很多,也非常深入,下面列出很少的一部分,非常感谢这些作者的分享。
http://gaojiewyh.iteye.com/blog/1775238
http://android.group.iteye.com/group/wiki/3083-java-sync-communication
http://blog.csdn.net/topwqp/article/details/8733063
http://fanning.iteye.com/blog/1449987
http://www.cnblogs.com/leizhilong/archive/2008/04/01/1133728.html
http://www.cnblogs.com/techyc/archive/2013/03/19/2969677.html
http://blog.csdn.net/super254/article/details/5055507
http://stackoverflow.com/questions/2144851/synchronization-in-vectors-in-java
http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
前几天部门开会,听闻部门的小领导喜欢在面试的时候问应聘人synchronized关键字的用法,当时在座的兄弟都震惊了。这个关键字平时都在用,但具体到理论,可能就说不上了。感觉平时都忙干活了,被杂七杂八的事情围绕,业务需求虽然可以完成,但一些基础的东西时间长了不去接触,反而慢慢的都生疏了,这可不好,假如哪天有机会去面试新公司时被类似的问题问倒,岂不是对不起自己七、八年的工作经验和现任东家。
小领导举例说,有几个问题是他经常用的,以我面试应聘的兄弟时候,也可以拿来用用。
1、什么场景下使用synchronized关键字?
很显然,数据需要在多个线程中共享访问时,需要对数据进行保护,假如不存在这种场景,那么就不需要考虑多线程保护,否则会影响代码的运行效率。
2、这些场景下如果不使用synchronized关键字,会有什么后果?
多线程访问冲突,比如数据不一致、数据不正确,对容器操作时容易抛出并发修改异常。
3、vector是线程安全的吗?
简单场景下,vector是线程安全的,但在复杂场景下,仍然需要程序员使用额外的手段来保证同步,否则仍然存在不一致的可能。
。。。