java synchronized
基本上,所有并发的模式在解决线程冲突问题的时候,都是采用序列化共享资源的方案。这意味着在给定时刻只允许一个任务访问该资源。这个一般通过在代码上加一条锁语句实现,因为锁语句产生一种互斥排斥的效果,这种机制常常被称为互斥机制。
线程是簇拥在共享资源门前,并不是排队进入,可以通过yield()和setPriority()来给线程调度提供建议,但这些建议未必会有多大的效果。这取决与你的具体平台和vm的实现:)--//from 《think in java》
java中提供关键字synchronized,为防止资源冲突提供内置支持。当他用来修饰一个方法或者代码块的时候,能够保证在同一时间最多只有一个线程访问执行该方法或者代码块;关于synchronized用于方法,用于代码块,用于静态方法可以参考博客Java中Synchronized的用法
sychronized(this)的理解:
this它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。=.= 那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱 :) 使用三个实例加强理解:
示例一:
public class Thread1 implements Runnable { public void run() { synchronized(this) { //枷锁 for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " synchronized loop " + i); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) { Thread1 t1 = new Thread1(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); //A线程先执行完毕,再执行B线程 ta.start(); tb.start(); } }
结果:
A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4
B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
B synchronized loop 3
B synchronized loop 4
示例二:
public class Thread2 { public void m4t1() { synchronized (this) {//枷锁1 int i = 5; while (i-- > 0) { System.out .println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } } public void m4t2() { synchronized (this) {//枷锁2 int i = 5; while (i-- > 0) { System.out .println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(300);//休眠短一些 } catch (InterruptedException ie) { } } } } public static void main(String[] args) { final Thread2 myt2 = new Thread2(); Thread t1 = new Thread(new Runnable() { public void run() { myt2.m4t1();//A线程只调用了枷锁的m4t1(),B线程调用枷锁的m4t2(),仍然需要等待A执行完毕 } }, "A"); Thread t2 = new Thread(new Runnable() { public void run() { myt2.m4t2(); } }, "B"); t1.start(); t2.start(); } }
结果:
A : 4
A : 3
A : 2
A : 1
A : 0
B : 4
B : 3
B : 2
B : 1
B : 0
也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
示例三:
public class Thread3 { public void m4t1() { synchronized (this) {//枷锁 int i = 5; while (i-- > 0) { System.out .println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } } public void m4t2() {int i = 5;//不枷锁 while (i-- > 0) { System.out .println(Thread.currentThread().getName() + " : " + i); try { Thread.sleep(300); } catch (InterruptedException ie) { } } } public static void main(String[] args) { final Thread3 myt3 = new Thread3(); Thread t1 = new Thread(new Runnable() { public void run() { myt3.m4t1(); // } }, "A"); Thread t2 = new Thread(new Runnable() { public void run() { myt3.m4t2(); } }, "B"); t1.start(); t2.start(); } }
结果: (具有不确定性)
A : 4
B : 4
B : 3
A : 3
B : 2
B : 1
A : 2
B : 0
A : 1
A : 0
当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
总结:所有的对象都有单一的锁(也成为监视器)。当在对象上调用任意的synchronized方法的时候,此对象都被加锁,这时调用该对象上其他的synchronized方法只有等待前一个方法调用完毕并释放所之后才能调用。
注意:在使用并发的时候,将域设置为private时非常重要的。否则,synchronized关键字就不能防止其他任务直接访问域,这样就会产生冲突。
one more thing:
一个任务可以多次获得对象的锁,如果一个方法在同一对象上调用了第二个方法,后者又调用了同一对象上的另一个方法,就会发生这样的情况。JVM负责跟踪对象被加锁的次数。如果一个对象被完全解锁,其计数变为0.每当任务离开一个synchronized方法,计数递减,当计数为0,锁被完全释放,此时别的任务就可以使用此资源:)
针对每一个类,也有一个锁(作为类的class对象的一部分),所以synchronized static方法可以在类的范围类防止对static数据的并发访问。