首先提出问题:
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同步方法的时候,呈现同步效果。
每个优秀的人,都有一段沉默的时光。不抱怨,不诉苦,最后度过那段感动自己的日子。