sychronized用法

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块时,另一个线程仍可以访问该objectsynchronized同步代码块

 

/**
 * 这个例子是要说明一个线程访问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

三、当一个线程访问objectsynchronized同步代码部分时,其他线程对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
A:1
A:2
A:3
A:4
B:0
B:1
B:2
B:3
B:4

  

四、当一个线程访问object的一个synchronized同步代码块时,它就获得了同步对象锁,其他所有线程对该object对象的所有同步代码部分访问都暂时被阻塞

/**
 * 这个例子是想说明一个线程在执行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
A:1
A:2
A:3
A:4
B:0
B:1
B:2
B:3
B:4

五、以上规则对其他对象锁同样适用。

 

仔细看1234的区别。

 

总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。

 

我们需要明确几点:

A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。

B.每个对象只有一个锁(lock)与之相关联。

C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

<!--EndFragment-->

猜你喜欢

转载自junzai.iteye.com/blog/1977532