一、概念
synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的。
锁机制有如下两种特性:
-
互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。
-
可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。
二、对象锁和类锁
- 对象锁 在 Java 中,每个对象都会有一个 monitor 对象,这个对象其实就是 Java
对象的锁,通常会被称为“内置锁”或“对象锁”。类的对象可以有多个,所以每个对象有其独立的对象锁,互不干扰。 - 类锁
在 Java 中,针对每个类也有一个锁,可以称为“类锁”,类锁实际上是通过对象锁实现的,即类的 Class 对象锁。每个类只有一个 Class 对象,所以每个类只有一个类锁。
synchronized 的用法可以从两个维度上面分类:
三、根据使用对象和使用方法分类
根据修饰对象分类
synchronized 可以修饰方法和代码块
修饰代码块
- synchronized(this|object) {}
- synchronized(类.class) {}
修饰方法
- 修饰非静态方法
- 修饰静态方法
根据获取的锁分类
获取对象锁
- synchronized(this|object) {}
- 修饰非静态方法
获取类锁
- synchronized(类.class) {}
- 修饰静态方法,非静态方法
四、总结
- 对于静态方法采用类锁;
- 对于非静态方法,同一个实例的线程访问会被拦截,非同一实例可以同时访问。 即此时是默认对象锁(this)。
- 只要采用类锁,就会拦截所有线程,只能让一个线程访问。
- 对于对象锁(this),如果是同一个实例,就会按顺序访问,但是如果是不同实例,就可以同时访问。
- 如果对象锁跟访问的对象没有关系,那么就会都同时访问。
五、测试代码
测试类锁
public class testMain {
private static int count;
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
//每个线程让count自增100次
for (int i = 0; i < 100; i++) {
synchronized (this.getClass()){
count++;
}
}
}
}).start();
}
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(count);
}
}
此处用this.getclass()为类锁,显示结果200
使用this为对象锁,显示结果小于等于200随机数
测试对象锁
import org.jetbrains.annotations.NotNull;
public class testMain2 {
private static int count;
public static void main(String[] args) {
Runnable target = getTarget();
for (int i = 0; i < 2; i++) {
new Thread(target).start();
}
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(count);
}
@NotNull
private static Runnable getTarget() {
return new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch ( Exception e ) {
e.printStackTrace();
}
//每个线程让count自增100次
for (int i = 0; i < 100; i++) {
synchronized (this) {
count++;
}
}
}
};
}
}
此处无论是否使用this.getClass 还是 this 均返回200,对象锁生效
文章参考博客园 huansky synchronized(this) 与synchronized(class) 之间的区别