一,synchronized
以虚拟的叫号系统为例
采用并发程序叫号时会出现跳号、重号、超过最大值等现象。
参照JMM模型,https://blog.csdn.net/qq_22059611/article/details/95211836
可知由于工作空间数据对其他线程不可见、且叫好操作不为原子操作,所以会产生这类问题。
为了解决这个问题,引入了锁的概念,在一个线程对共享数据进行操作时,其他线程不能对该数据进行操作。
1,相关概念
为何利用锁可以实现同步?
锁机制有如下两种特性:
互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。
可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。
2,synchronized的用法
a、同步方法
(1) 同步非静态方法
Public synchronized void methodName(){
……
}
(2) 同步静态方法
Public synchronized static void methodName(){
……
}
b、同步代码块
synchronized(this|object) {}
synchronized(类.class) {}
Private final Object MUTEX =new Object();
Public void methodName(){
Synchronized(MUTEX ){
……
}
}
根据获取的锁分类
1、获取对象锁
synchronized(this|object) {}
修饰非静态方法
在 Java 中,每个对象都会有一个 monitor 对象,这个对象其实就是 Java 对象的锁,通常会被称为“内置锁”或“对象锁”。类的对象可以有多个,所以每个对象有其独立的对象锁,互不干扰。
2、获取类锁
synchronized(类.class) {}
修饰静态方法
在 Java 中,针对每个类也有一个锁,可以称为“类锁”,类锁实际上是通过对象锁实现的,即类的 Class 对象锁。每个类只有一个 Class 对象,所以每个类只有一个类锁。
用法说明
在 Java 中,每个对象都会有一个 monitor 对象,监视器。
1) 某一线程占有这个对象的时候,先monitor 的计数器是不是0,如果是0还没有线程占有,这个时候线程占有这个对象,并且对这个对象的monitor+1;如果不为0,表示这个线程已经被其他线程占有,这个线程等待。当线程释放占有权的时候,monitor-1;
2) 同一线程可以对同一对象进行多次加锁,+1,+1,重入性