class="p0" style="margin-top: 0pt; margin-bottom: 0pt;">Synchronized可分为synchronized方法和synchronized块。synchronized方法通常是在public之后返回值之前如:public?synchronized?void?A()
而synchronized块则是在方法里面,如:
public?void?B(){
Synchronized(object){
……
}
}
一、两个线程并发访问synchronized块时,一次只有一个线程能够访问,另一个线程只能等待当前线程访问完并释放synchronized块才能访问。
/** * 这个例子是想说明两个并发执行的线程需要同时访问一个对象的synchronized代码块时,同意时刻只有一个进程在执行, * 一个进程在执行时,另一个进程必须等待当前进程执行完 * @author zzj * */ public class Thread1 extends Thread{ public static void main(String[] args) { Thread1 t1 = new Thread1();//注意这里,因为ta,tb是两个并发执行的线程 Thread ta = new Thread(t1,"A"); Thread tb = new Thread(t1,"B"); ta.start(); tb.start(); } public void run(){ synchronized(this){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+"锁释放"+i); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
?结果:
A锁释放0
A锁释放1
A锁释放2
A锁释放3
A锁释放4
B锁释放0
B锁释放1
B锁释放2
B锁释放3
B锁释放4
?
二、当一个线程访问synchronized块时,另一个线程仍可以访问该object的非synchronized同步代码块
?
/** * 这个例子是要说明一个进程访问object的synchronized同步代码块时,其他进程可以同时访问object的非synchronized块 * @author zzj * */ public class Thread2{ public static void main(String[] args) { final Thread2 t2 = new Thread2();//注意这里,因为ta,tb是两个并发执行的线程 Thread ta = new Thread(new Runnable(){public void run(){ t2.A();}},"A"); Thread tb = new Thread(new Runnable(){public void run(){ t2.B();}},"B"); ta.start(); tb.start(); } //synchronized代码块 public void A(){ synchronized(this){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } //非synchronized代码块 public void B(){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
?结果:
A:0
B:0
A:1
B:1
A:2
B:2
B:3
A:3
B:4
A:4
?
三、当一个线程访问object的synchronized块时,其他线程对object的其他synchronized代码块的访问也讲被阻塞
?
/** * 这个例子是想说明两个并发的线程如果一个在访问synchronized同步代码块,其他线程对所有其他sychronized块的访问会被阻塞 * @author zzj * */ public class Thread3 extends Thread{ public static void main(String[] args) { final Thread3 t3 = new Thread3();//注意这里,因为ta,tb是两个并发执行的线程 Thread ta = new Thread(new Runnable(){public void run(){ t3.A();}},"A"); Thread tb = new Thread(new Runnable(){public void run(){ t3.B();}},"B"); ta.start(); tb.start(); } //synchronized代码块 public void A(){ synchronized(this){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } //非synchronized代码块 public void B(){ synchronized(this){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
?结果:
A:0
B:0
A:1
B:1
A:2
B:2
B:3
A:3
B:4
A:4
??
四、当一个线程访问object的一个synchronized同步代码块时,它就获得了同步对象锁,其他所有线程对该object对象的所有同步代码部分访问都暂时被阻塞(不一定是synchronized同步代码块,可能是synchronized方法)
/** * 这个例子是想说明一个进程在执行synchronized同步代码块时,其他进程要访问同步代码部分 * (不论是synchronized块还是方法都将被阻塞) * @author zzj * */ public class Thread4 { public static void main(String[] args) { final Thread4 t4 = new Thread4();//注意这里,因为ta,tb是两个并发执行的线程 Thread ta = new Thread(new Runnable(){public void run(){ t4.A();}},"A"); Thread tb = new Thread(new Runnable(){public void run(){ t4.B();}},"B"); ta.start(); tb.start(); } //synchronized代码块 public void A(){ synchronized(this){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } //非synchronized代码块 public synchronized void B(){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":"+i); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
?结果:
A:0
B:0
A:1
B:1
A:2
B:2
B:3
A:3
B:4
A:4
?
五、以上规则对其他对象锁同样适用。
?
仔细看1,2,3,4的区别。
?
总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object?reference(对象引用)、static函数和class?literals(类名称字面常量)身上。
?
我们需要明确几点:
A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
<!--EndFragment-->