注:本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即后台留言通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意
实现多线程同步的 synchronized 关键字
在 Java 中,多线程的使用已经成为了程序员必备技能之一,但是多线程开发往往涉及到线程间的数据共享,这时就需要对线程进行同步处理,防止出现竞争条件 (Race Condition) 导致的数据安全问题。Java 提供了一种解决方案,那就是 synchronized 关键字。本文将会介绍 synchronized 关键字的使用方法,以及其实现多线程同步的原理。
1. synchronized 关键字的基本用法
synchronized 关键字可以用于修饰以下两种对象:
1.1 方法
可以在方法的声明中使用 synchronized 关键字,此时 synchronized 关键字所修饰的是这个方法的对象。也就是说,此时 synchronized 可以保证同一时刻只能有一个线程访问该方法。例如:
```
public synchronized void method1() {
// ...
}
public void method2() {
synchronized(this) {
// ...
}
}
```
1.2 代码块
在 Java 中,可以在代码块内使用 synchronized 关键字,此时 synchronized 相当于修饰在代码块内部的对象,可以传入任意对象。当且仅当当前线程获得该对象的锁时才可以执行该代码块。例如:
```
public void method1() {
synchronized(this) {
// ...
}
}
public void method2() {
Object obj = new Object();
synchronized(obj) {
// ...
}
}
```
2. synchronized 关键字的实现原理
synchronized 关键字可以保证同步代码块在任意时刻只能被一个线程访问,而其他线程必须等待锁释放后才能继续执行。那么 synchronized 关键字是如何实现同步的呢?
其实 synchronized 的实现原理主要依靠两个特性:监视器 (Monitor) 和管程 (Monitor Object)。
2.1 监视器基础
Java 对象内部都有一个监视器,其实就是一个计数器。当线程进入 synchronized 块时,将会尝试获取对象的监视器,如果监视器的计数为 0,说明对象没有被占用,申请线程可以立即获得该监视器并将计数器加 1,表示该线程占用了该监视器。当其他线程也需要访问同步代码块时,就会尝试获取对象的监视器,如果此时监视器的计数器不为 0,说明该对象已经被其他线程占用,此时申请线程将会阻塞直至监视器计数为 0,然后申请线程可以获得该监视器并将计数器加 1。
当该线程完成同步代码块的执行后,会释放该监视器并将计数器减 1,其他线程可以继续通过竞争该监视器来进入同步代码块。
2.2 管程实现
当一个线程所占用的监视器中的锁需要在其它线程中被释放时,并且其它线程需要被唤醒,这时就需要使用管程实现。管程实际上是对监视器的补充,在 ThreadPoolExecutor、ReentrantLock 等中都使用了管程的实现。
管程实现是通过一个队列来实现的,称为条件队列 (Condition Queue),它里面存放了互斥访问同步块的线程对象。每次当一个线程访问同步块时,都会将这个线程的对象加入到条件队列中,并且调用 wait() 方法,让该线程进入睡眠状态。
当另外一个线程释放了该同步块的锁时,它会同时唤醒条件队列中的头结点中的线程,这时头结点中的线程就会重新进入就绪状态,并与其它线程竞争该同步块的锁。
3. 总结
synchronized 关键字是 Java 中用于实现多线程同步的一种机制,它的实现原理主要依托于 Java 对象内部的监视器以及通过管程实现的条件队列。在实际使用中,可以将 synchronized 关键字用于修饰方法或者代码块,以及传入不同的对象实现多种不同的同步处理方式。同时,也需要注意使用 synchronized 关键字的时机以及同步块的代码长度,以避免线程阻塞导致程序的性能下降。
本文标题:synchronized(实现多线程同步的 synchronized 关键字) 本文链接:http://www.cswwyl.com/meiwei/22704.html