1.synchronized修饰非静态方法
public class MyObject {
synchronized public void method1(){
System.out.println("method1");
method2();
}
synchronized public void method2(){
System.out.println("method2");
}
public void method3(){
System.out.println("method3");
}
}
synchronized放在public之前或者之后没有区别。
首先实例化MyObject类:MyObject myObject = new MyObject();
1、修饰某个类中的非静态方法时,synchronized锁的并不是所修饰的方法,而是当前类的对象。也就是锁的是实例化的对象: myObject
。
2、当线程A获得myObject
对象的锁之后正在调用myObject.method1()
方法,这时线程B想要调用myObject.method2()
方法则需要等待,也就是同步。结论:A线程先持有myObject 对象的锁,线程B如果这时想调用myObject 对象中的任意一个synchronized类型方法都需要等待,也就是同步。
3、新实例化一个对象:MyObject myObject2 = new MyObject();
这时候线程A调用myObject.method1()
方法,线程B调用myObject2.method1()
方法,这时是异步的,因为分别是两把不同锁。
4、线程A先持有myObject 对象的锁,线程B可以异步调用myObject对象中没被synchronized修饰的方法。如:
线程A调用myObject.method1()
;线程B调用myObject.method3()
;这时执行结果是异步的。
5、synchronized拥有锁重入功能,也就是当线程A调用myObject.method1()
方法,myObject.method1()
调用本类中的其他synchronized方法/块时,是永远可以得到锁的。锁重入也支持父子类继承的情况:子类可以通过锁重入调用父类的同步方法。
6、子类重写了父类的同步方法,如果子类中重写的方法不使用synchronized关键字,那么该方法就变成了非同步方法,加上synchronized关键字后就变成了同步方法。
2.synchronized(this)代码块
public class MyObject {
public void method1(){
System.out.println("method1异步执行!");
synchronized (this){
System.out.println("method1");
}
}
public void method2(){
System.out.println("method2异步执行!");
synchronized (this){
System.out.println("method2");
}
}
public void method3(){
System.out.println("method3");
}
}
首先实例化MyObject类:MyObject myObject = new MyObject();
1、和synchronized方法一样synchronized(this)代码块也是以当前实例对象作为锁,因此A线程先持有myObject 对象的锁,线程B如果这时想调用myObject 对象中的任意一个synchronized(this)代码块都需要等待,也就是同步。
2、synchronized(this)的优点:可以只同步需要同步的部分代码,没在同步代码块中的代码可以异步执行,这相对synchronized方法来说增加了执行效率。如:线程A和线程B都调用myObject.method1()
方法,这时synchronized (this)代码块上面的那行输出代码是异步的。
3.synchronized(非this对象)代码块
public class MyObject {
public void method1(){
String s = new String();
synchronized (s){
System.out.println("method1");
}
}
public void method2(){
System.out.println("method2异步执行!");
synchronized (this){
System.out.println("method2");
}
}
synchronized public void method3(){
System.out.println("method3");
}
}
首先实例化MyObject类:MyObject myObject = new MyObject();
1、synchronized(非this对象)代码块写法是将括号中的“非this对象”加锁。
2、synchronized(非this对象)代码块优点:synchronized(非this对象)代码块和当前对象中其他同步方法是异步的,因为是两把不同的锁,不与其他锁this同步方法争抢this锁,可以提升运行效率。如:线程A调用myObject.method1()
方法,线程B调用myObject.method2()
或myObject.method3()
方法,这时是异步的,因为分别是两把不同的锁。
3.如:
class MyObject2 {
public void method1(MyObject3 myObject3){
synchronized (myObject3){
System.out.println("method1");
}
}
}
class MyObject3 {
synchronized public void method1(){
System.out.println("method1");
}
}
class MyThread2 extends Thread{
private MyObject2 myObject2;
private MyObject3 myThread3;
public MyThread2(MyObject2 myThread2,MyObject3 myThread3){
this.myObject2 = myThread2;
this.myThread3 = myThread3;
}
@Override
public void run() {
myObject2.method1(myThread3);
}
}
class MyThread3 extends Thread{
private MyObject3 myThread3;
public MyThread3(MyObject3 myThread3){
this.myThread3 = myThread3;
}
@Override
public void run() {
myThread3.method1();
}
}
class test{
public static void main(String[] args) throws InterruptedException {
MyObject2 myObject2 = new MyObject2();
MyObject3 myObject3 = new MyObject3();
MyThread2 myThread2 = new MyThread2(myObject2,myObject3);
MyThread3 myThread3 = new MyThread3(myObject3);
myThread2.start();
myThread3.start();
}
}
这时两线程执行是同步的,因为使用的同一把锁。代码示例中是synchronized方法,synchronized(this)代码块和synchronized同理。
4.静态synchronized方法与synchronized(class)代码块
class Service{
synchronized public static void method1(){
System.out.println("静态方法上加锁");
}
public static void method2(){
synchronized (Service.class){
System.out.println("synchronized(class)代码块");
}
}
}
1、*.java对应的class类对象是单例的,在static方法上使用synchronized关键字时,是当前静态方法所在的类对应的class类的单例对象作为锁。class锁对所有对象实例起作用,也就是所有实例对象是同一把锁。而非static方法上使用synchronized关键字是其所对应的单个实例作为锁,多个实例对象的时候就是多把不同的锁了。
2、synchronized(class)代码块和synchronized static方法同理。
参考书籍:Java多线程编程核心技术(第2版)高洪岩 著