对象锁和类锁

对象锁

Synchronized修饰非静态方法,是对调用该方法的对象加锁,俗称“对象锁”。

这里的对象加锁并非是说执行该加锁方法的时候整个对象的所有成员都不允许其他线程访问了,

而是说该对象内所有的加锁的非静态方法共用这一把锁, 一个加锁非静态方法执行, 另一个加锁非静态方法不能执行,要等持有锁的线程释放锁, 不同对象之间的方法不互相作用

这里举第一个例子:

两个线程执行同一个对象不同加锁非静态方法, 预期互斥执行,即同一对象的两个加锁的非静态方法共用该锁:

package test;
 
public class Test1 {
	synchronized void  fun1() throws InterruptedException {
		System.out.println("加锁的方法1开始执行");
		Thread.sleep(2000);
		System.out.println("加锁的方法1执行结束");
	}
	synchronized void  fun2() throws InterruptedException {
		System.out.println("加锁的方法2开始执行");
		Thread.sleep(2000);
		System.out.println("加锁的方法2执行结束");
	}
}

两个线程分别执行同一个对象的两个方法 

package test;
 
public class TestSyntro {
 
	public static void main(String[] args) {
		Test1 obj1=new Test1();
		
		new Thread() {
			@Override
			public void run() {
				try {
					obj1.fun1();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}; 
		}.start();
		
		new Thread() {
			@Override
			public void run() {
				try {
					obj1.fun2();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}; 
		}.start();
	}
}

结果:

 说明两个方法是互斥执行的, 共用一把锁

那么我们把第二个方法的锁去掉,看看同一个对象加锁的方法运行时不加锁的方法是否可以执行:

(由于篇幅,以后例子都由上例微改得到, 不再重复贴代码, 也是因为本来就是给新手看, 太长反而让人晕,注意描述,加锁与否, 几个对象,静态,非静态)

 说明同一对象加锁方法不影响为加锁的方法

我们用两个线程执行两个对象的加锁方法, 预期不互斥, 证明不同对象不共用非静态锁:

 

 

只是改了第二个线程的执行方法的对象:

package test;
 
public class TestSyntro {
 
	public static void main(String[] args) {
		Test1 obj1=new Test1();
		Test1 obj2=new Test1();
		new Thread() {
			@Override
			public void run() {
				try {
					obj1.fun1();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}; 
		}.start();
		
		new Thread() {
			@Override
			public void run() {
				try {
					obj2.fun2();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}; 
		}.start();
	}
}

 不互斥说明不同对象的非静态锁不共用

 

Synchronized修饰静态方法,是对该类对象加锁,俗称“类锁”。

同样, 这里的对象加锁并非是说执行该加锁方法的时候整个类的所有(静态)成员都不允许其他线程访问了,

而是说该类内所有的加锁的静态方法共用这一把锁, 一个加锁静态方法执行, 同类另一个加锁静态方法不能执行,要等持有锁的线程释放锁

还是上面的程序, 两个方法全是静态, 都加锁,:

两个线程分别执行该类两个对象的静态加锁方法, 预期互斥执行, 证明与对象无关

互斥执行, 说明该锁由类中静态方法共用

我们把一个方法写成静态, 一个不静态, 都加锁, 由两个类调用同一个对象的两个方法, 预期不互斥, 证明静态与非静态方法不共用锁:

不互斥,说明静态与非静态方法不共用锁

 

synchronized方法与synchronized代码块的区别
synchronized methods() {} 与 synchronized (this) {} 之间并没有什么区别。

只是前者便于阅读理解,而后者可以更精确的控制冲突限制访问区域(粒度更小),锁的范围没有变,锁住的时间变短了因而性能更好。

synchronized(this)与synchronized(class)的区别

首先this 和class 分别是两把不同的锁,不会存在class被获取,this就要等的现象。
synchronized加在一个类的普通方法上,那么相当于synchronized(this)
如果synchronized加载一个类的静态方法上,那么相当于synchronized(Class对象)。
 

总结:

  • 静态方法的锁属于类, 一个类中所有加锁的静态方法共用该锁
  • 非静态方法的锁属于对象,  一个对象中所有加锁的非静态方法共用, 和静态方法的锁不同而互不相干
  • 加锁的方法的执行不会影响同一个类/对象中未加锁的方法的执行(因为其他方法没有锁呀)

有参考下文:

https://www.jianshu.com/p/8327c5c15cb8