关于单例模式的学习,我认为看这篇文章http://blog.csdn.net/haoel/article/details/4028232 + http://www.cnblogs.com/BeyondAnyTime/archive/2012/05/14/2498940.html足矣
针对http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html的测试以及各种学习。
概念:
synchronized是Java 语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
- 当两个并发线程访问同一个对象中这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
- 然而,当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
- 尤其关键的是,当一个线程访问对象的一个synchronized(this)同步代码块时,其他线程对对象所有其他synchronized(this)同步代码块的访问将被阻塞。
- 当一个线程访问对象的一个synchronized(this)同步代码块时,它就获得了这个对象的对象锁。结果,其他线程对该对象中所有同步代码部分的访问都被暂时阻塞你
- synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果 再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
- 无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
- 每个对象只有一个锁(lock)与之相关联
- 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
例子:
public class Thread1 implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 5; i++) {
System.err.println(Thread.currentThread().getName() + "synchronized loop" + i);
}
}
public static void main(String[] args){
Thread1 t1 = new Thread1();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}
输出:
可以看出两个线程是混在一起执行的,正如陈大神所言,JVM 的即时编译器中存在指令重排序的优化,加上synchronized(this)之后:
public class Thread1 implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (this) {
for (int i = 0; i < 5; i++) {
System.err.println(Thread.currentThread().getName() + "synchronized loop" + i);
}
}
}
public static void main(String[] args){
Thread1 t1 = new Thread1();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}
输出:
输出结果呈现正常顺序。说明了观点一的正确性。
哎呀太累了,不想把人家代码贴过来了。总结性的五点已经给出,牢记之后就正确使用synchronized