那问题来了,使用 synchronized 加锁 this 和 class 的区别是什么?不都是加锁同一个类吗?
答案还真不是,加锁 this 和 class 区别还是很大的。下面我们通过以下 4 个示例,来看二者之间的区别。 1.加锁 class 共享一个类实例
首先,我们创建 5 个线程,调用同一个对象下 synchronized 加锁的 class 代码,具体示例如下:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 创建当前类实例
final SynchronizedExample example = new SynchronizedExample();
// 创建 5 个线程执行任务
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 调用 synchronized 修饰的 class 方法
example.classMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* synchronized 修饰的 class 方法
* @throws InterruptedException
*/
public void classMethod() throws InterruptedException {
synchronized (SynchronizedExample.class) {
System.out.println(String.format("当前执行线程:%s,执行时间:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
以上程序的执行结果如下:
从上述结果可以看出,这 5 个线程共享的是同一把锁。 2.加锁 class 创建多个实例
接下来,我们创建 5 个线程,调用不同对象下 synchronized 加锁的 class 代码,具体示例如下:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 创建 5 个线程执行任务
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 创建类实例
SynchronizedExample example = new SynchronizedExample();
// 调用 synchronized 修饰的 class 方法
example.classMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* synchronized 修饰的 class 方法
* @throws InterruptedException
*/
public void classMethod() throws InterruptedException {
synchronized (SynchronizedExample.class) {
System.out.println(String.format("当前执行线程:%s,执行时间:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
以上程序的执行结果如下:
从上述结果可以看出,虽然是不同的对象,但它们使用的仍然是同一把锁。 3.加锁 this 共享一个类实例
接下来,我们创建 5 个线程,调用 synchronized 加锁 this 的示例。首先我们这 5 个线程调用同一个对象的加锁方法,示例代码如下:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 创建当前类实例
final SynchronizedExample example = new SynchronizedExample();
// 创建 5 个线程执行任务
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 调用 synchronized 修饰的 this 方法
example.thisMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* synchronized 修饰的 this 方法
* @throws InterruptedException
*/
public void thisMethod() throws InterruptedException {
synchronized (this) {
System.out.println(String.format("当前执行线程:%s,执行时间:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
以上程序的执行结果如下:
从上述结果可以看出,以上线程使用的都是同一把锁。 4.加锁 this 创建多个类实例
最后一个示例最为特殊,我们使用 synchronized 加锁 this,让这 5 个线程调用各自创建对象的方法,具体示例如下:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 创建 5 个线程执行任务
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 创建(多个)类实例
SynchronizedExample example = new SynchronizedExample();
// 调用 synchronized 修饰的 this 方法
example.thisMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* synchronized 修饰的 this 方法
* @throws InterruptedException
*/
public void thisMethod() throws InterruptedException {
synchronized (this) {
System.out.println(String.format("当前执行线程:%s,执行时间:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
以上程序的执行结果如下:
从上述结果可以看出,当使用 synchronized 加锁 this 时,如果线程调用的不是同一个对象,那么这些线程之间使用的锁都是自己独立的锁,这个结果就和 synchronized 加锁 class 的结果完全不同了。 总结
通过以上 4 个示例我们可以得出结论,当使用 synchronized 加锁 class 时,无论共享一个对象还是创建多个对象,它们用的都是同一把锁,而使用 synchronized 加锁 this 时,只有同一个对象会使用同一把锁,不同对象之间的锁是不同的。
原文链接:https://mp.weixin.qq.com/s/7DTk5CV5FSOsa5fSN_V26w