synchronized锁的什么资源
前言
我们都用过synchronized这个关键字,常见的使用方式是这样synchronized(资源){代码},这是显示的声明锁资源,很明显知道要竞争锁资源是什么。
我们也知道在两个不同方法上架synchrinized关键字,这两个方法在不同线程中会互相等待,他们好像获取的是同一个资源,那这个锁资源是什么呢?是方法的引用obj::method?下面我们来验证一下
声明一个加synchronized的类
public class TestSynchronize {
static Object get1 = new Object();
public synchronized void get() {
// synchronized (this) {
System.out.println(Thread.currentThread().getName()+"get得到锁"+this);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// }
}
public synchronized void ge2t() {
System.out.println(Thread.currentThread().getName()+"ge2t得到锁"+this);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static synchronized void staticget() {
System.out.println(Thread.currentThread().getName()+"staticget得到锁");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static synchronized void staticge2t() {
System.out.println(Thread.currentThread().getName()+"staticge2t得到锁");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
执行代码测试
- 我们先看下非静态方法的情况
public static void main(String[] args) {
TestSynchronize stu = new TestSynchronize();
new Thread(()->{
synchronized (stu) {
System.out.println(Thread.currentThread().getName()+"获取锁"+stu+"\t"+System.currentTimeMillis());
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"释放锁"+"\t"+System.currentTimeMillis());
}
},"a").start();;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"尝试"+"\t"+System.currentTimeMillis());
stu.get();
System.out.println(Thread.currentThread().getName()+"结束"+"\t"+System.currentTimeMillis());
},"b").start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"尝试"+"\t"+System.currentTimeMillis());
stu.ge2t();
System.out.println(Thread.currentThread().getName()+"结束"+"\t"+System.currentTimeMillis());
},"c").start();
}
a获取锁Test.Test.TestSynchronize@1d1ae28f 1635507748132
b尝试 1635507748133
c尝试 1635507748133
a释放锁 1635507753143
c\t ge2t得到锁Test.Test.TestSynchronize@1d1ae28f 1635507753143
c结束 1635507756155
b get得到锁Test.Test.TestSynchronize@1d1ae28f 1635507756155
b结束 1635507759166
我们看待a线程获取锁之后,b,c线程都在等待锁,c获取锁后b线程在等待锁
- 在看下静态方法上的synchronized
public static void main(String[] args) {
new Thread(()->{
synchronized (TestSynchronize.class) {
System.out.println(Thread.currentThread().getName()+"获取锁"+TestSynchronize.class +"\t"+System.currentTimeMillis());
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"释放锁"+"\t"+System.currentTimeMillis());
}
},"astatic").start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"尝试"+"\t"+System.currentTimeMillis());
TestSynchronize.staticget();
System.out.println(Thread.currentThread().getName()+"结束"+"\t"+System.currentTimeMillis());
},"estatic").start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"尝试"+"\t"+System.currentTimeMillis());
TestSynchronize.staticge2t();
System.out.println(Thread.currentThread().getName()+"结束"+"\t"+System.currentTimeMillis());
},"fstatic").start();
}
astatic 获取锁class Test.Test.TestSynchronize 1635507551822
estatic 尝试 1635507551822
fstatic 尝试 1635507551823
astatic 释放锁 1635507556825
fstatic\t staticge2t得到锁 1635507556825
fstatic 结束 1635507559834
estatic\t staticget得到锁 1635507559834
estatic 结束 1635507562843
我们可以看到astatic线程获取锁后,estatic fstatic两个线程中的静态方法都在等待锁,fstatic得到锁之后estatic 在等待fstatic释放锁。
结论
- 当在静态方法上加synchronized时,实际上锁的资源是class这个类等效代码是synchronized (TestSynchronize.class) ,所以两个静态方法都加synchronized关键字时竞争的是同一个锁资源。
- 当在普通方法上加锁时,实际上锁的是实体对象,也就是this,上面打印出来是TestSynchronize@1d1ae28f这个对象,所以两个普通方法竞争的也是同一个锁资源,也会互相等待。