网站首页 > 精选教程 正文
监视器(Monitor)是在Java中管理并发访问共享资源的机制,包括一个锁和一个或多个条件变量,主要用于协调线程之间的同步和通信,在Java中,每个Java对象都自带了一个监视器,这样使得每个对象都可以作为同步操作的基本单位。
下面我们就来介绍一下监视器在Java中的工作原理和线程同步的实现方式。
Synchronized关键字
synchronized是Java中提供的用来实现同步机制的关键字,可以用来修饰方法或者代码块,它确保在同一时间只有一个线程可以执行,从而实现线程同步。
- 同步方法:在方法声明中使用public synchronized void method() { ... }。这里,锁是当前实例对象(对于实例方法)或类对象(对于静态方法)。
- 同步代码块:在代码块中使用synchronized(obj) { ... }。这里,锁是obj对象。
内置锁(对象锁)
每个Java对象都有一个内置锁,当一个线程进入synchronized方法或synchronized代码块时,它必须首先获得这个锁。如果锁已经被其他线程持有,那么该线程将被阻塞,直到锁被释放。
监视器的实现原理
监视器的实现依赖于JVM的底层机制,主要涉及到如下的几个方面的内容。
对象头(Object Header)
每个Java对象在内存中都有一个对象头,其中存储了锁状态和线程持有信息,而对象头中的具体信息因JVM实现而异,但通常包括锁标志位、持有锁的线程ID和其他元数据。
锁的状态
JVM通过对象头的标志位来管理锁的状态,常见的锁状态包括,如下一些。
- 无锁(Unlocked):对象未被任何线程持有。
- 偏向锁(Biased Locking):对象被单个线程持有,并优化了锁的获取和释放过程。
- 轻量级锁(Lightweight Locking):对象被多个线程竞争,但没有发生严重的竞争
- 重量级锁(Heavyweight Locking):对象发生了严重的锁竞争,进入操作系统的重量级锁机制。
锁竞争和性能优化
JVM在实现监视器时,会通过多种优化技术以减少锁竞争对性能的影响,例如偏向锁和轻量级锁都是为了减少线程竞争时的开销,提高程序的并发性能。
- 偏向锁:当一个线程多次获取同一个锁时,锁会偏向该线程,减少锁的获取和释放操作。
- 轻量级锁:通过CAS(Compare-And-Swap)操作实现锁的获取和释放,适用于低竞争场景。
- 重量级锁:当竞争激烈时,JVM使用操作系统提供的线程阻塞和唤醒机制。
监视器的工作原理
监视器的工作机制可以分为如下的三个部分
进入监视器
当一个线程尝试进入synchronized方法或代码块的时候,它必须要获取到相应的监视器的锁,如果这个锁是可以使用的,也就是说没有被其他的线程占用,那么线程就会获取锁并且进入到临界区中。如果锁是不可用的,那么线程就会被阻塞,放入到该监视器的等待队列中,直到锁被释放。
执行临界区代码
当线程获取到锁之后,就会执行synchronized方法或代码块中的代码,期间,其他线程尝试进入该临界区的时候,就会被阻塞,这样就确保了只有一个线程能够执行该代码。
退出监视器
当线程退出synchronized方法或代码块时,它会释放监视器锁,如果有其他线程在等待该锁,则其中一个线程将被唤醒并尝试重新获得锁。
条件变量和等待/通知机制
Java提供了Object类中的wait(), notify(), notifyAll()方法,用于实现更高级的线程间通信。
- wait():当一个线程调用对象的wait()方法时,它将释放该对象的锁,并进入该对象的等待队列,直到其他线程调用notify()或notifyAll()方法唤醒它。
- notify():唤醒正在等待该对象锁的单个线程。如果有多个线程在等待,则选择一个(由JVM实现决定)进行唤醒。
- notifyAll():唤醒所有正在等待该对象锁的线程。这些线程会再次竞争对象锁,只有一个线程能成功获得锁并继续执行。
Java中的监视器示例
以下是一个简单的示例,展示如何使用synchronized关键字和wait/notify方法实现线程同步和通信。
class SharedResource {
private int count = 0;
public synchronized void increment() {
count++;
notify(); // 通知等待的线程
}
public synchronized void decrement() {
while (count == 0) {
try {
wait(); // 释放锁并等待
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
count--;
}
public synchronized int getCount() {
return count;
}
}
public class MonitorExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
// 线程1:增加资源计数
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
resource.increment();
System.out.println("Incremented: " + resource.getCount());
}
});
// 线程2:减少资源计数
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10; i++) {
resource.decrement();
System.out.println("Decremented: " + resource.getCount());
}
});
t1.start();
t2.start();
}
}
在这个示例中increment()方法和decrement()方法使用synchronized关键字来确保对共享资源的互斥访问。wait()和notify()方法用于实现线程之间的通信,当计数为0时,调用decrement()方法的线程将进入等待状态,直到有其他线程调用increment()方法并通知它。
总结
在Java中,监视器通过内置锁和条件变量来实现线程同步。通过synchronized关键字,线程可以安全地进入和退出临界区,而通过wait(), notify(), notifyAll()方法,线程可以实现复杂的等待/通知机制。监视器确保了在任何时刻,只有一个线程可以执行受保护的代码,从而避免并发冲突。
猜你喜欢
- 2024-11-07 JMX带你透视Java应用,实现应用程序的动态实时监控
- 2024-11-07 java应用监控和分析思路 java监控gc
- 2024-11-07 巧用JAVA监控工具2——jvisualvm java jvm 监控
- 2024-11-07 老技术新谈,Java应用监控利器JMX(1)
- 2024-11-07 Javaagent 使用 - 探针 jsp探针
- 2024-11-07 详解docker容器的资源监控方案 docker容器资源限制
- 2024-11-07 性能诊断利器 JProfiler 快速入门和最佳实践
- 2024-11-07 java监控工具(1) java视频监控
- 2024-11-07 java通过插桩的概念来完成监控系统的设计
- 2024-11-07 高性能、无侵入的 Java 性能监控神器
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)