之前一直觉得synchronized就是使代码块具有原子性。听了马士兵老师的一个课,说其实锁的是对象,不是很理解。
我的问题是:在下面这个程序里,synchronized到底锁的是整个方法,还是T这个类?
class T{
private int Tcount=10;
public synchronized void m1() {
while(Tcount>4) {
System.out.print(Thread.currentThread());
System.out.println(Tcount);
Tcount--;
}
}
}
我通过实验来说明这个问题:
1.我在课程里看他举的例子
在T里定义两个方法m1,m2,m1加锁。
class T{
private int Tcount=10;
public synchronized void m1() {
while(Tcount>4) {
System.out.print(Thread.currentThread());
System.out.println(Tcount);
Tcount--;
}
}
public void m2() {
while(Tcount>0) {
System.out.print(Thread.currentThread());
System.out.println(Tcount);
Tcount--;
}
}
}
调用:定义两个线程分别调用m1和m2
public static void main(String args[]) {
//MyRunnable mr=new MyRunnable();
T t=new T();
Thread thread=new Thread(t::m1,"m1");
Thread thread2=new Thread(t::m2,"m2");
thread.start();
thread2.start();
}
结果:
m1和m2是交叉执行的。这很正常,毕竟第二个线程又没调用m1()对吧。(这个实验很容易误导,让人以为锁的就是m1这个方法。)
2、接下来是重点
如果让m2也加上锁。线程调用不变。
class T{
private int Tcount=10;
public synchronized void m1() {
while(Tcount>4) {
System.out.print(Thread.currentThread());
System.out.println(Tcount);
Tcount--;
}
}
public synchronized void m2() {
while(Tcount>0) {
System.out.print(Thread.currentThread());
System.out.println(Tcount);
Tcount--;
}
}
}
如果synchronized锁的是方法,那就应该是T这个类有两个锁,第一把锁m1,第二把锁m2.这样执行结果应该是thread和thread2各不影响。
如果synchronized锁的是类,那就是说如果thread调用了m1(),锁了T这个类,那此时m2()也就不能用了。这样对应的结果就应该是thread执行完,释放了T的锁,thread2才会执行。
进行实验:
public static void main(String args[]) {
//MyRunnable mr=new MyRunnable();
T t=new T();
Thread thread=new Thread(t::m1,"m1");
Thread thread2=new Thread(t::m2,"m2");
thread.start();
thread2.start();
}
输出结果:
可以看到,thread和thread2是分开的。
所以Synchronized锁的是T这个类!
但是回到第一个实验,既然m1前加了Synchronized,按这个说法,那T不就被锁了,为什么m2还能被调用?
以下是我的理解:
这是因为m2()这个方法调用的时候根本不需要管它锁没锁。
被Synchronized修饰的方法调用前需要去看看这个类有没有被锁,而没被Synchronized修饰的方法不需要去检查。也就是正确理解一下锁这个类是什么意思。
我的理解,锁这个类其实就是锁的所有被Synchronized关键字修饰的内容。
其实说类也是不准确的,应该说是对象。 每个线程都有自己的堆,是在堆上new出来的那个对象实体上加的锁。
这个也很好做实验:
public static void main(String args[]) {
//MyRunnable mr=new MyRunnable();
T t1=new T();
Thread thread=new Thread(t1::m1,"m1");
T t2=new T();
Thread thread2=new Thread(t2::m2,"m2");
thread.start();
thread2.start();
}
得到的结果也是交叉执行的。
——————————————————————————————
此外,我们知道以下两种写法是等价的。这也说明锁的是this类。
public synchronized void m1() {
while(Tcount>4) {
System.out.print(Thread.currentThread());
System.out.println(Tcount);
Tcount--;
}
}
public void m1() {
Synchronized(this){
while(Tcount>4) {
System.out.print(Thread.currentThread());
System.out.println(Tcount);
Tcount--;
}
}
}