相对于场景一:synchronized包裹代码块,synchronized修饰方法的场景要简单明朗许多。因为无论被修饰的方法是静态还是成员,线程访问它时它都只能指定特定的锁。
而不像synchronized包裹代码块场景下,类A的对象a即可以指定自己为锁,也可以指定类B的对象b为锁,也可以指定类A对应的Class对象为锁,也可以指定类B对应的Class对象为锁……简直生活不能自理 (~﹏~)
假设:有类A,类A对象a,类A同步成员方法 methodMember(),类A同步静态方法 methodStatic();
先上结论:a.当线程需要进入对象a同步成员方法methodMember()时,必须且只能申请methodMember()对应的对象(也即是对象a)作为对象锁。
b.当线程需要进入类A同步静态方法methodStatic()时,必须且只能申请methodStatic()对应的类(也即是类A)作为类锁。
一、修饰成员方法
一个线程访问synchronized修饰的成员方法,并成功取得对应的对象a作为锁。随后的线程想要进入
1)同对象的其他同步成员方法;(现象一)
2)所有以对象a作为对象锁的同步代码块,无论是否同对象、是否同类、是否处于静态方法(现象二)
时,均会发生竞争。
a.验证现象一
为SynchronizedVerify类添加如下main():
public static void main(String[] args){
final SynchronizedVerify sv = new SynchronizedVerify();
new Thread(){//定为线程一
public void run() { sv.methodStyle(); };
}.start();
new Thread(){//定为线程二
public void run() { sv.methodNormal(); };
}.start();
}
sv.methodStyle() + sv.methodNormal()输出(无竞争):
methodStyle:0 |Thread-0
methodNormal:0 |Thread-1
methodNormal:1 |Thread-1
methodStyle:1 |Thread-0
methodNormal:2 |Thread-1
methodStyle:2 |Thread-0
将线程二调用的方法改为methodContrast()
sv.methodStyle() + sv.methodContrast()输出(竞争):
methodStyle:0 |Thread-0
methodStyle:1 |Thread-0
methodStyle:2 |Thread-0
methodContrast:0 |Thread-1
methodContrast:1 |Thread-1
methodContrast:2 |Thread-1
b.验证现象二
为SynchronizedVerify类添加如下main():
public static void main(String[] args){
final SynchronizedVerify sv = new SynchronizedVerify();
new Thread(){//定为线程一
public void run() { sv.methodStyle(); };
}.start();
new Thread(){//定为线程二
public void run() { sv.blockDiffObj(); };
}.start();
}
sv.methodStyle() + sv.blockDiffObj()输出(无竞争):
methodStyle:0 |Thread-0
blockDiffObj:0 |Thread-1
methodStyle:1 |Thread-0
blockDiffObj:1 |Thread-1
methodStyle:2 |Thread-0
blockDiffObj:2 |Thread-1
线程二调用方法改为:blockOneself()
sv.methodStyle() + sv.blockOneself()输出(竞争):
methodStyle:0 |Thread-0
methodStyle:1 |Thread-0
methodStyle:2 |Thread-0
blockOneself:0 |Thread-1
blockOneself:1 |Thread-1
blockOneself:2 |Thread-1
其他情况原理类似,不再累述。
二、修饰静态方法
一个线程访问synchronized修饰的静态方法,并成功取得对应的类A作为锁。随后的线程想要进入
1)同对象的其他同步静态方法;(现象三)
2)所有以类A作为类锁的同步代码块,无论是否同对象、是否同类、是否处于静态方法(现象四)
时,均会发生竞争。
a.验证现象三
为SynchronizedVerify类添加如下main():
public static void main(String[] args){
new Thread(){//定为线程一
public void run() { SynchronizedVerify.methodStatic(); };
}.start();
new Thread(){//定为线程二
public void run() { SynchronizedVerify.methodStaticNormal(); };
}.start();
}
SynchronizedVerify.methodStatic() + SynchronizedVerify.methodStaticNormal()输出(无竞争):
methodStatic:0 |Thread-0
methodStaticNormal:0 |Thread-1
methodStaticNormal:1 |Thread-1
methodStatic:1 |Thread-0
methodStatic:2 |Thread-0
methodStaticNormal:2 |Thread-1
将线程二调用的方法改为methodStaticContrast()
SynchronizedVerify.methodStatic() + SynchronizedVerify.methodStaticContrast()输出(竞争):
methodStatic:0 |Thread-0
methodStatic:1 |Thread-0
methodStatic:2 |Thread-0
methodStaticContrast:0 |Thread-1
methodStaticContrast:1 |Thread-1
methodStaticContrast:2 |Thread-1
b.验证现象四
为SynchronizedVerify类添加如下main():
public static void main(String[] args){
final SynchronizedVerify sv = new SynchronizedVerify();
new Thread(){//定为线程一
public void run() { SynchronizedVerify.methodStatic(); };
}.start();
new Thread(){//定为线程二
public void run() { sv.blockOneself(); };
}.start();
}
SynchronizedVerify.methodStatic() + sv.blockOneself()输出(无竞争):
methodStatic:0 |Thread-0
blockOneself:0 |Thread-1
methodStatic:1 |Thread-0
blockOneself:1 |Thread-1
methodStatic:2 |Thread-0
blockOneself:2 |Thread-1
线程二调用方法改为:blockClass()
SynchronizedVerify.methodStatic() + sv.blockClass()输出(竞争):
methodStatic:0 |Thread-0
methodStatic:1 |Thread-0
methodStatic:2 |Thread-0
blockClass:0 |Thread-1
blockClass:1 |Thread-1
blockClass:2 |Thread-1
其他情况原理类似,不再累述。