博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

多线程 synchronized关键字锁对象和方法区别

Posted on 2018-08-02 20:20  南国木棉  阅读(461)  评论(0编辑  收藏  举报

  首先提出问题:

  1 当一个类中有多个synchronized方法的时候,多线程访问不同的方法会不会阻塞?

  2 synchronized(this)和synchronized(非this 对象x)的区别是什么?

  下面我们实验:

  为图省事,将两个问题放在一起验证。

  定义7个方法,分别在主线程中调用,

  

public class MyMethod {

	synchronized public void methodA() {
		try {
			System.out.println(Thread.currentThread().getName()+"  into methodA  " +System.currentTimeMillis());
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	synchronized public void methodB() {
		try {
			System.out.println(Thread.currentThread().getName()+"  into methodB  "  +System.currentTimeMillis());
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	synchronized public void methodC(){
		try {
			System.out.println(Thread.currentThread().getName()+"  into methodC  "  +System.currentTimeMillis());
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	synchronized public void methodD(){
		try {
			System.out.println(Thread.currentThread().getName()+"  into methodD  "  +System.currentTimeMillis());
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	public void methodE(){
		try {
			synchronized (this) {
				System.out.println(Thread.currentThread().getName()+"  into methodE  "  +System.currentTimeMillis()+"  **");
				Thread.sleep(1000);
			}
		} catch (Exception e) {
		}
	}
	public void methodF(String lock){
		try {
			synchronized (lock) {
				System.out.println(Thread.currentThread().getName()+"  into methodF  "  +System.currentTimeMillis()+"  **");
				Thread.sleep(1000);
			}
		} catch (Exception e) {
		}
	}
	
	public void methodJ(String lock){
		try {
			synchronized (lock) {
				System.out.println(Thread.currentThread().getName()+"  into methodJ  "  +System.currentTimeMillis()+"  **");
				Thread.sleep(1000);
			}
		} catch (Exception e) {
		}
	}
}

 main方法

public class Run {

	public static void main(String[] args) {
		
		MyMethod method=new MyMethod();
		String lock="";
		//开启四个线程,分别调用四个方法
		for (int i = 0; i < 7; i++) {
			final int temp=i;
			Thread thread=new Thread(new Runnable() {
				@Override
				public void run() {
					switch (temp) {
					case 0:method.methodA();break;
					case 1:method.methodB();break;
					case 2:method.methodC();break;
					case 3:method.methodD();break;
					case 4:method.methodE();break;
					case 5:method.methodF(lock);break;
					case 6:method.methodJ(lock);break;
					}
				}
			});
			thread.start();
		}
		
		

	}

}

  为了省事,本人一起写在for循环中,本人测试的顺序是。

  注调其他case,调用A ,B,C,D四个方法

控制台

Thread-0  into methodA  1533211474985
Thread-3  into methodD  1533211475986
Thread-2  into methodC  1533211476986
Thread-1  into methodB  1533211477987

  可以发现,同一个类中多个synchronized同步方法是阻塞的。

  解开第五个,调用A,B,C,D,E五个方法

控制台

Thread-0  into methodA  1533211570137
Thread-4  into methodE  1533211571137  **
Thread-3  into methodD  1533211572138
Thread-2  into methodC  1533211573139
Thread-1  into methodB  1533211574139

  看时间戳会发现,方法E和其他方法阻塞,所以,synchronized同步方法锁是当前对象。

  在解开第六个,调用A,B,C,D,E,F六个方法

控制台

Thread-1  into methodB  1533211712907
Thread-5  into methodF  1533211712907  **
Thread-4  into methodE  1533211713908  **
Thread-3  into methodD  1533211714909
Thread-2  into methodC  1533211715910
Thread-0  into methodA  1533211716910

  可以发现,F和B的时间是一模一样的,所以,他们之间是异步的,因为锁的对象不同。而另外的方法和代码块锁的都是当前对象,所以互斥。

  解开第七个,七个方法全部调用。

控制台

Thread-0  into methodA  1533211922515
Thread-5  into methodF  1533211922516  **
Thread-4  into methodE  1533211923516  **
Thread-6  into methodJ  1533211923516  **
Thread-3  into methodD  1533211924517
Thread-2  into methodC  1533211925518
Thread-1  into methodB  1533211926519

  可以发现,F和J是阻塞的。因为锁的是同一个对象。

总结:synchronized 锁方法锁的是当前对象,synchronized(this)锁的也是当前对象。所以同一个类中,当有多个synchronized方法的时候,他们是互相阻塞的,同时也会阻塞synchronized(this)代码块中的内容。

      synchronized(this)时锁当前对象,此时一个类中的多个synchronized方法,或者锁当前对象的会互相阻塞。而锁非this对象的时候,和此时异步的,并不会阻塞。而锁非this对象的时候,当非this对象是同一个对象的时候,也会呈现同步效果。

   synchronized(非this对象x)格式的写法,是将x对象当做"对象监视器",这样就有下面三个结论:

  1)当多个线程访问synchronized(非this对象x){}代码块的时候,呈现同步效果。

  2)当其他线程执行x对象中的synchronized(this){}代码块的时候,呈现同步效果。

  3)当其他线程执行x对象中的synchronized同步方法的时候,呈现同步效果。

 

 

  每个优秀的人,都有一段沉默的时光。不抱怨,不诉苦,最后度过那段感动自己的日子。