1. synchronized加在普通方法上
public synchronized void method1() {
System.out.println(Thread.currentThread().getName() + "访问了同步方法1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void method2() {
System.out.println(Thread.currentThread().getName() + "访问了同步方法2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
1.1 通过同一个对象引用去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method1());
Thread t2 = new Thread(() -> demo1.method2());
t1.start();
t2.start();
测试结果:会阻塞,因为synchronized加在方法上锁住的是当前类的引用对象
1.2 通过不同对象引用去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
SynchronizedDemo demo2 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method1());
Thread t2 = new Thread(() -> demo2.method2());
t1.start();
t2.start();
测试结果:不会阻塞,因为锁住的是当前类的引用对象,而调用使用的是不同的对象
2. synchronized加在静态方法上
public static synchronized void method1() {
System.out.println(Thread.currentThread().getName() + "访问了同步方法1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void method2() {
System.out.println(Thread.currentThread().getName() + "访问了同步方法2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2.1 通过同一个对象去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method1());
Thread t2 = new Thread(() -> demo1.method2());
t1.start();
t2.start();
测试结果:会阻塞,因为方法被static修饰,表示该方法属于类,而Class只有一份,所以锁住的是同一个对象
2.2 通过不同对象去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
SynchronizedDemo demo2 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method1());
Thread t2 = new Thread(() -> demo2.method2());
t1.start();
t2.start();
测试结果:会阻塞,原因同上
3. 同步代码块锁住this
public void method3() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "访问了this的同步代码块3");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void method4() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "访问了this的同步代码块4");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.1 通过同一个对象去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method3());
Thread t2 = new Thread(() -> demo1.method4());
t1.start();
t2.start();
测试结果:会阻塞,因为this为对象实例,所以锁住的是同一个对象
3.2 通过不同对象去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
SynchronizedDemo demo2 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method3());
Thread t2 = new Thread(() -> demo2.method4());
t1.start();
t2.start();
测试结果:不会阻塞,因为使用的是两个不同的对象实例
总结:synchronized加在普通方法上和锁住this作用相同,都是锁当前对象实例
4. 同步代码块锁住不同的Object
Object lock1 = new Object();
Object lock2 = new Object();
public void method5() {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + "访问了lock1的同步代码块5");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void method6(){
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + "访问了lock2的同步代码块6");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4.1 通过相同的对象去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method5());
Thread t2 = new Thread(() -> demo1.method6());
t1.start();
t2.start();
测试结果:不会阻塞,因为锁住的是同一引用下的不同对象实例
5. 同步代码块锁住相同的Object
public void method5() {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + "访问了lock1的同步代码块5");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void method6(){
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + "访问了lock1的同步代码块6");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5.1 使用相同对象去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method5());
Thread t2 = new Thread(() -> demo1.method6());
t1.start();
t2.start();
测试结果:会阻塞,因为锁住的是同一引用下的相同对象实例,如果锁住不同对象或使用不同对象实例去调用则不会阻塞
6. 同步代码块锁住类对象
public void method7() {
synchronized (SynchronizedDemo.class) {
System.out.println(Thread.currentThread().getName() + "访问了Class的同步代码块5");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void method8(){
synchronized (SynchronizedDemo.class) {
System.out.println(Thread.currentThread().getName() + "访问了Class的同步代码块6");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
6.1 使用不同对象去调用
SynchronizedDemo demo1 = new SynchronizedDemo();
SynchronizedDemo demo2 = new SynchronizedDemo();
Thread t1 = new Thread(() -> demo1.method7());
Thread t2 = new Thread(() -> demo2.method8());
t1.start();
t2.start();
测试结果:会阻塞,由于锁住的是Xxx.class所以锁住的是Class对象,这和被标记为static的方法锁住的都是同一个对象,所以无论使用相同引用还是不同引用都会被阻塞住,因为Class只有一个。