synchronized关键字---使用基础

    synchronized关键字是JAVA中内置的语言级同步原语,可以通过使用这个关键字实现多线程间访问之间的同步。

    synchronized关键字可以作为函数的修饰符,也可以直接在函数语句中使用,也就是平时说的同步方法和同步语句。从作用域上上来看,它可以分为作用于某个实例对象内和某个类的范围内。先看看单个对象内的用法:

 1).   同步方法示例

public class Tester{
	public synchronized void test(){
	}
}

      此时,synchronized 锁定的就是调用该同步方法对象。也就是说同一Tester对象在不同线程中调用test()方法时,必须要等前一线程执行完成之后另一线程才能执行test()方法

  2).  同步语句示例

public class Tester{
	public void test(){
		synchronized(lock){
			//代码....
		} 
	}
}

       lock可以称为对象锁,它可以是this或任何需要被锁定的对象,如果没有特别想锁定的对象,只是想实现某一代码块的同步,也可以将lock 写成任意object对象o,只要保证不同线程执行该test方法时,lock是同一个o对象即可

 

      以上均是在某个对象的作用域内使用同步,也可以实现在类的范围内的某个方法的同步,或是让一个类的所有对象都在某个代码块的使用上同步:

public synchronized static void test(){
	
}

 

public class Tester{
	public void test(){
		synchronized(Tester.class){
			//代码....
		} 
	}
}

       此时的对象锁是Tester类的所有对象,即假设Tester t1,Tester t2两个对象,当一个线程在执行完t1的同步语句之前,另一个线程也不能执行t2的同步语句。

 

synchronized的使用方法如上,下面说一下使用该关键字时的不同的情况:

      (1)当多个并发线程访问同一对象的synchronized方法或语句时,一个时间内只能有一个线程可以执行该同步方法或同步语句。另一个线程必须等待当前线程执行完才能执行。

 

      (2)当线程A访问一个对象的某一同步方法1是,其他线程必须等待A执行完1方法才能执行其他同步方法,即对该对象的其他同步方法的访问被阻塞。但是,其他线程仍然可以访问该对象任何非同步方法

 

线程A(为增加对比性,线程均休眠10millis)

	public void run(){
		t.test1();
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

 线程B

	public void run(){
		t.test2();
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

 主函数

	public static void main(String args[]){
		Tester t=new Tester();
		ThreadA ta=new ThreadA(t);
		ThreadB tb=new ThreadB(t);
		ta.start();
		tb.start();	
	}

未使用同步的示例

class Tester{		
	public  void test1(){	
			for(int i=0;i<10;i++){
				System.out.println(">>>>>>test1"+">>"+i);
			}
	}	
	public  void test2(){
			for(int i=0;i<10;i++){
				System.out.println("test2-----"+""+i);
			}
	}	
}

运行后结果V_1

使用同步方法

	public synchronized void test1(){	
			for(int i=0;i<5;i++){
				System.out.println(">>>>>>test1"+">>"+i);
			}
	}	
	public synchronized void test2(){
			for(int i=0;i<5;i++){
				System.out.println("test2-----"+""+i);
			}
	}	

运行后结果V_2

通过运行结果对比,可知,当tester对象在线程A中调用test1()时,该对象在线程B中调用同是同步方法的test2()时被阻塞。


    (3)上述情况对于sychronzied(this)或是synchronized(lock)同步语句中的其他对象锁同样使用,但要保证lock是同一个对象,否则没有同步效果。

    另外,synchronized关键字无法继承。

 

   分析完各种使用情况,最后说一下自己对线程同步的理解吧。拿前面的test()方法来说,不同线程中的同一个tester是彼此独立的,将一个tester对象看成一栋大楼,test()方法是房间,一个线程中使用tester.test()方法就好比该线程在tester大楼中开了一个新的test()房间,多个线程在并发的开房间,谁先开,使用的进度如何彼此之间并没有约束和影响。但是如果把tester对象锁定了,就像把这个大楼上了锁,一次只能允许一个线程进入(针对要使用上了锁的方法或代码块的线程而言),那么这个大楼里的所有房间(所有同步方法和同步代码块)就只有一个线程可以使用,这样,各线程对该tester对象的使用就是互斥的了,亦即有了同步的效果。

       

猜你喜欢

转载自zyj--july.iteye.com/blog/1771981