synchronized七种场景应用总结

本篇博客是慕课网Java高并发之魂:synchronized深度解析的笔记

一、两个线程同时访问一个对象的同步方法

分析:首先是同一个对象,并且是同步方法,这属于对象锁中的普通同步方法锁,效果是线程顺序执行;

public class SynchTest implements Runnable{

	static SynchTest synchTest=new SynchTest();
	
	@Override
	public void run() {
		method();
	}
	
	// 同步方法锁
	public synchronized void method() {
		System.out.println(Thread.currentThread().getName()+" 开始执行");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 执行完毕");
	}
	
	public static void main(String[] args) {
		// 两个线程
		Thread t1=new Thread(synchTest);
		Thread t2=new Thread(synchTest);
		t1.start();
		t2.start();
		while (t1.isAlive() || t2.isAlive()) {
			
		}
		System.out.println("finished");
	}
}

执行结果

synchronized七种场景应用总结_第1张图片

二、两个线程访问的两个对象的同步方法

分析:访问不同的对象,如果要实现同步的话,锁的级别应该到类锁,但题中是同步方法,属于对象级别的,所以,不同对象不受干扰,线程并行运行;

public class SynchTest2 implements Runnable{

	static SynchTest2 synchTest1=new SynchTest2();
	static SynchTest2 synchTest2=new SynchTest2();
	
	@Override
	public void run() {
		method();
	}
	
	// 同步方法锁
	public synchronized void method() {
		System.out.println(Thread.currentThread().getName()+" 开始执行");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 执行完毕");
	}
	
	public static void main(String[] args) {
		// 两个线程,不同对象
		Thread t1=new Thread(synchTest1);
		Thread t2=new Thread(synchTest2);
		t1.start();
		t2.start();
		while (t1.isAlive() || t2.isAlive()) {
			
		}
		System.out.println("finished");
	}
}

运行结果:

三、两个线程访问的是synchronized静态方法

分析:在上篇文章中提到synchronized修饰的静态方法,锁的级别是类锁,不管是不是同一个对象,线程都是顺序同步执行,synchronized关键字生效;

public class SynchTest2 implements Runnable{

	static SynchTest2 synchTest1=new SynchTest2();
	static SynchTest2 synchTest2=new SynchTest2();
	
	@Override
	public void run() {
		method();
	}
	
	// 同步静态方法锁
	public synchronized static void method() {
		System.out.println(Thread.currentThread().getName()+" 开始执行");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 执行完毕");
	}
	
	public static void main(String[] args) {
		// 两个线程,不同对象
		Thread t1=new Thread(synchTest1);
		Thread t2=new Thread(synchTest2);
		t1.start();
		t2.start();
		while (t1.isAlive() || t2.isAlive()) {
			
		}
		System.out.println("finished");
	}
}

执行结果:

四、同时访问同步方法和非同步方法

分析:一个线程访问同步方法,一个线程访问非同步方法,两者是否受影响?synchronized影响范围是它修饰的方法体,对其它方法不受影响,结论就是非同步方法不受影响,该怎么运行还怎么运行,即使修饰的是静态方法,也不受影响,因为锁类型不同

public class SynchTest2 implements Runnable{

	static SynchTest2 synchTest=new SynchTest2();
	
	/*
	 *  如果是线程1直接执行方法1,线程2执行方法2
	 */
	public void run() {		
		if("Thread-0".equals(Thread.currentThread().getName())) {
			method1();
		}else {
			method2();
		}
	}
	
	// 同步方法
	public synchronized void method1() {
		System.out.println(Thread.currentThread().getName()+" 开始执行同步方法");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 同步方法执行完毕");
	}
	// 非同步方法
	public void method2() {
		System.out.println(Thread.currentThread().getName()+" 开始执行非同步方法");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 非同步方法执行完毕");
	}
	
	public static void main(String[] args) {
		// 两个线程,同一对象
		Thread t1=new Thread(synchTest);
		Thread t2=new Thread(synchTest);
		t1.start();
		t2.start();
		while (t1.isAlive() || t2.isAlive()) {
			
		}
		System.out.println("finished");
	}
}

运行结果:

五、访问同一个对象的不同的普通同步方法

分析:有点绕,没办法,面试题经常就是很绕的,最好把面试官也给绕进去算了;同一个对象的两个线程,其中一个线程访问类的同步方法1,另一个线程访问同步方法2,两者受影响吗?普通同步方法默认是(this)对象级别的,锁类型相同,所以,同一个对象的线程访问两个方法是受影响的,顺序执行,不会并行的;

public class SynchTest2 implements Runnable{

	static SynchTest2 synchTest=new SynchTest2();
	
	/*
	 *  如果是线程1直接执行方法1,线程2执行方法2
	 */
	public void run() {		
		if("Thread-0".equals(Thread.currentThread().getName())) {
			method1();
		}else {
			method2();
		}
	}
	
	// 同步方法1
	public  synchronized void method1() {
		System.out.println(Thread.currentThread().getName()+" 开始执行同步方法1");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 同步方法1执行完毕");
	}
	// 同步方法2
	public synchronized void  method2() {
		System.out.println(Thread.currentThread().getName()+" 开始执行同步方法2");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 同步方法2执行完毕");
	}
	
	public static void main(String[] args) {
		// 两个线程,同一对象
		Thread t1=new Thread(synchTest);
		Thread t2=new Thread(synchTest);
		t1.start();
		t2.start();
		while (t1.isAlive() || t2.isAlive()) {
			
		}
		System.out.println("finished");
	}
}

运行结果;

六、同时访问静态synchronized方法和非静态synchronized方法

分析:这个情况比较复杂,根据以上结论可以得出,只要两个线程的锁类型相同,就是同步,不相同,则并行,不受干扰!

           静态同步方法锁级别是类锁,非静态同步方法级别是对象锁,所以并行,不受干扰的;

public class SynchTest2 implements Runnable{

	static SynchTest2 synchTest1=new SynchTest2();
	static SynchTest2 synchTest2=new SynchTest2();
	/*
	 *  如果是线程1直接执行方法1,线程2执行方法2
	 */
	public void run() {		
		if("Thread-0".equals(Thread.currentThread().getName())) {
			method1();
		}else {
			method2();
		}
	}
	
	// 静态同步方法
	public  static synchronized void method1() {
		System.out.println(Thread.currentThread().getName()+" 开始执行静态同步方法");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 静态同步方法执行完毕");
	}
	// 非静态同步方法
	public synchronized void method2() {
		System.out.println(Thread.currentThread().getName()+" 开始执行非静态同步方法");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 非静态同步方法执行完毕");
	}
	
	public static void main(String[] args) {
		// 两个线程,同一对象
		Thread t1=new Thread(synchTest1);
		Thread t2=new Thread(synchTest1);
		t1.start();
		t2.start();
		while (t1.isAlive() || t2.isAlive()) {
			
		}
		System.out.println("finished");
	}
}

执行结果

synchronized七种场景应用总结_第2张图片

延伸一下:两个都是静态方法呢?由于都是类锁,不管线程是不是一个对象的,都是顺序执行,同步运作(下个例子就用这个来验证);

对象锁 同步代码块锁 普通方法锁
类锁 static方法锁 *.class锁

七、 方法抛异常后是否会释放锁

       答案是:会自动释放锁,具体原理后续展开讨论;

public class SynchTest2 implements Runnable{

	static SynchTest2 synchTest1=new SynchTest2();
	static SynchTest2 synchTest2=new SynchTest2();
	/*
	 *  如果是线程1直接执行方法1,线程2执行方法2
	 */
	public void run() {		
		if("Thread-0".equals(Thread.currentThread().getName())) {
			method1();
		}else {
			method2();
		}
	}
	
	// 静态同步方法
	public  static synchronized void method1() {
		System.out.println(Thread.currentThread().getName()+" 开始执行静态同步方法1");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// 抛出异常
		int num=1/0;
		System.out.println(Thread.currentThread().getName()+" 静态同步方法1执行完毕");
	}
	// 非静态同步方法
	public static synchronized void method2() {
		System.out.println(Thread.currentThread().getName()+" 开始执行静态同步方法2");
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+" 静态同步方法2执行完毕");
	}
	
	public static void main(String[] args) {
		// 两个线程
		Thread t1=new Thread(synchTest1);
		Thread t2=new Thread(synchTest2);
		t1.start();
		t2.start();
		while (t1.isAlive() || t2.isAlive()) {
			
		}
		System.out.println("finished");
	}
}

运行结果:

synchronized七种场景应用总结_第3张图片

你可能感兴趣的:(java)