谁会被锁住
一般来说,synchronized
从锁的是谁的纬度上一共有两种情况;
- 锁住类
- 锁住实例对象
类锁与实例对象锁的区别
实例锁
类声明后,new出来的实例对象,在堆中都有自己的独立空间和引用地址,这时候我们可以认为这些实例都是独立的个体
,所以在实例上加的锁与其它的实例就没有关系,互不影响
类锁
类信息是存放在方法区的,整个JVM中只有一份
,方法区是被所有线程共享
的,所以类也是被所有线程共享的。
而静态成员(static修饰的成员、方法)是跟类一起加载的,也是存放在方法区,被所有线程共享。
参考链接:面试官:请说以下对象锁与类锁的区别
synchronized 的各种场景
若synchronized
在静态方法上进行了声明则锁的是这个类,也就是我们常说的类锁
,如下:
public static synchronized void test(){};
若synchronized
在普通方法上
进行了声明,或者是synchronized(this)
,则锁的是这个类的实例对象
,如下:
public class Test{
// synchronized 在普通方法`进行了声明
public synchronized void test1(){};
// 同步代码块 这里锁的也是这个类的实例对象
public void test(){
synchronized(this){
...
}
}
}
同步代码块synchronized(Demo.class)
锁的是Demo这个类
:如下:
public class Demo{
}
public class Test{
public void test(){
synchronized(Demo.class)
}
}
synchronized(object)
锁的是这个实例对象
,如下:
public class Demo{
}
public class Test{
private Demo demo = new Demo();
public void test(){
synchronized(demo)
}
}
参考链接
有一个点需要特别注意:
类锁与实例锁其实都是加锁,并不是将整个类锁住了,也不是这个类/实例中所有方法
都被锁住了,而是控制了某个synchronized方法
或者synchronized代码块
的访问
。
参考下方代码:
public class Test{
public void test1(){
System.out.println("test1");
}
public void test2(){
synchronized (this){
System.out.println("test2");
}
}
}
test2中有加锁 synchronized (this)
,若想继续执行后续代码,需要先获取当前实例对象(Test实例对象)的钥匙,而钥匙是只有一份的,当有并发时,钥匙只能归一个线程使用,在使用过程中,其它线程需排队等候。从而达到控制test2方法同步代码块的访问
而test1中是没有加锁的,可进行并发处理,线程与线程之间同时执行也没有关系
也不知道有没有说清楚,没说清楚可评论区一起讨论~