synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候
下面细细道来……
先说第一种情况,ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B2个线程去竞
争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,
转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是ReentrantLock
不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己(或者别的线程中断
它),ReentrantLock处理了这个中断,并且不再等待这个锁的到来,完全放弃。(如果你没有了解java的中断机制,请参考下相关资料,再回头
看这篇文章,80%的人根本没有真正理解什么是java的中断,呵呵)
这里来做个试验,首先搞一个Buffer类,它有读操作和写操作,为了不读到脏数据,写和读都需要加锁,我们先用synchronized原语来加锁,如下:
Java代码
public class Buffer {
private Object lock;
public Buffer() {
lock = this;
}
public void write() {
synchronized (lock) {
long startTime = System.currentTimeMillis();
System.out.println("开始往这个buff写入数据…");
for (;;)// 模拟要处理很长时间
{
if (System.currentTimeMillis()
- startTime > Integer.MAX_VALUE)
break;
}
System.out.println("终于写完了");
}
}
public void read() {
synchronized (lock) {
System.out.println("从这个buff读数据");
}
}
}
接着,我们来定义2个线程,一个线程去写,一个线程去读。
Java代码
public class Writer extends Thread {
private Buffer buff;
public Writer(Buffer buff) {
this.buff = buff;
}
@Override
public void run() {
buff.write();
}
}
public class Reader extends Thread {
private Buffer buff;
public Reader(Buffer buff) {
this.buff = buff;
}
@Override
public void run() {
buff.read();//这里估计会一直阻塞
System.out.println("读结束");
}
}
好了,写一个Main来试验下,我们有意先去“写”,然后让“读”等待,“写”的时间是无穷的,就看“读”能不能放弃了。
Java代码
public class Test {
public static void main(String[] args) {
Buffer buff = new Buffer();
final Writer writer = new Writer(buff);
final Reader reader = new Reader(buff);
writer.start();
reader.start();
new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
for (;;) {
//等5秒钟去中断读
if (System.currentTimeMillis()
- start > 5000) {
System.out.println("不等了,尝试中断");
reader.interrupt();
break;
}
}
}
}).start();
}
}
我们期待“读”这个线程能退出等待锁,可是事与愿违,一旦读这个线程发现自己得不到锁,就一直开始等待了,就算它等死,也得不到锁,因为写线程要21亿秒
才能完成 T_T
,即使我们中断它,它都不来响应下,看来真的要等死了。这个时候,ReentrantLock给了一种机制让我们来响应中断,让“读”能伸能屈,勇敢放弃
对这个锁的等待。我们来改写Buffer这个类,就叫BufferInterruptibly吧,可中断缓存。
Java代码
import java.util.concurrent.locks.ReentrantLock;
public class BufferInterruptibly {
private ReentrantLock lock = new ReentrantLock();
public void write() {
lock.lock();
try {
long startTime = System.currentTimeMillis();
System.out.println("开始往这个buff写入数据…");
for (;;)// 模拟要处理很长时间
{
if (System.currentTimeMillis()
- startTime > Integer.MAX_VALUE)
break;
}
System.out.println("终于写完了");
} finally {
lock.unlock();
}
}
public void read() throws InterruptedException {
lock.lockInterruptibly();// 注意这里,可以响应中断
try {
System.out.println("从这个buff读数据");
} finally {
lock.unlock();
}
}
}
当然,要对reader和writer做响应的修改
Java代码
public class Reader extends Thread {
private BufferInterruptibly buff;
public Reader(BufferInterruptibly buff) {
this.buff = buff;
}
@Override
public void run() {
try {
buff.read();//可以收到中断的异常,从而有效退出
} catch (InterruptedException e) {
System.out.println("我不读了");
}
System.out.println("读结束");
}
}
/**
* Writer倒不用怎么改动
*/
public class Writer extends Thread {
private BufferInterruptibly buff;
public Writer(BufferInterruptibly buff) {
this.buff = buff;
}
@Override
public void run() {
buff.write();
}
}
public class Test {
public static void main(String[] args) {
BufferInterruptibly buff = new BufferInterruptibly();
final Writer writer = new Writer(buff);
final Reader reader = new Reader(buff);
writer.start();
reader.start();
new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
for (;;) {
if (System.currentTimeMillis()
- start > 5000) {
System.out.println("不等了,尝试中断");
reader.interrupt();
break;
}
}
}
}).start();
}
}
分享到:
相关推荐
本文将深入探讨标题和描述中提及的各种锁,包括乐观锁、悲观锁、分布式锁、可重入锁、互斥锁、读写锁、分段锁、类锁以及行级锁。 1. **乐观锁**:乐观锁假设多线程环境中的冲突较少,所以在读取数据时不加锁,只有...
在Java并发编程中,锁是控制多线程访问共享资源的...最后,对于源码阅读爱好者来说,深入研究JVM源码中的锁实现细节,如`ObjectMonitor`类,可以进一步提升对并发编程的理解,有助于在实际开发中更好地应用这些知识。
它具有可重入性,即一个线程可以多次获取同一锁,直到释放所有获取的锁。ReentrantLock还支持公平性和非公平性锁的配置,以及条件变量,这些特性使得ReentrantLock在某些场景下比`synchronized`更具优势。 除了...
在实际编程中,Java有`java.util.concurrent.locks`包提供了这些锁的实现,如`ReentrantLock`(可重入锁,互斥锁的一种),`ReadWriteLock`接口及其实现类`ReentrantReadWriteLock`,以及`Semaphore`类。C++的`std::...
### 深入研究Servlet线程安全性问题 #### 一、引言 Servlet技术作为Java Web开发中的核心组件之一,因其高效性和灵活性被广泛应用于Web应用程序的开发中。Servlet能够处理HTTP请求,并产生相应的响应。它的一个...
ReentrantLock具有可重入性,允许同一个线程多次获取同一把锁,避免了死锁的情况。相比synchronized,ReentrantLock提供了更丰富的锁操作,比如公平锁、非公平锁的选择,以及尝试锁、可中断锁和定时锁等功能。而...
3. **锁机制**:掌握synchronized关键字的使用,包括可重入锁、锁对象、锁升级和锁优化。同时,学习ReentrantLock、ReadWriteLock等高级锁的使用场景和优势。 4. **并发集合**:理解并使用并发安全的数据结构,如...
例如,我们可以使用`ReentrantLock`(可重入锁)来实现更复杂的并发控制策略。这个`JUCLock`的代码可能是用来演示如何使用`Lock`接口及其相关类,如如何实现公平锁、非公平锁,或者如何配合`Condition`来实现线程间...
Java并发工具包(J.U.C)是Java编程语言中用于并发编程的一系列工具包的统称,它包含了一系列方便实现多线程编程的类和接口...对于J.U.C的深入研究和实践,不仅能够提升Java编程能力,也会对编程思想有更深层次的理解。
在本实例中,可能包括ReentrantLock(可重入锁)的示例,它比synchronized更灵活,可以进行更复杂的操作,如尝试加锁、公平锁与非公平锁的选择,以及锁的条件(Condition)管理。 3. **CountDownLatch**: ...
在并发环境下,为了保证线程安全,ArrayBlockingQueue采用了ReentrantLock(可重入锁)来实现同步,并且在某些关键操作中使用了Condition(条件变量)来实现等待/通知机制。 1. 初始化:ArrayBlockingQueue在创建时...
线程在Java编程中是并发处理的核心概念,它允许程序同时执行多个任务,极大地...在深入研究这两个案例的同时,还可以尝试其他的线程同步机制,如Semaphore信号量、ReentrantLock可重入锁等,进一步拓宽我们的知识面。
10. Lock接口与ReentrantLock:对比synchronized,理解Lock接口的优势,重点研究可重入锁ReentrantLock的使用和特性。 三、并发集合 11. ConcurrentHashMap:深入理解并发容器ConcurrentHashMap的内部实现,包括...
3. **Lock接口与ReentrantLock**:Java提供了更细粒度的锁控制,比如ReentrantLock(可重入锁),它比synchronized更灵活,支持公平锁、非公平锁、尝试加锁、定时加锁和可中断加锁等多种特性。ReentrantLock还提供了...
在Java中,`java.util.concurrent.locks.Lock`接口及其实现如`ReentrantLock`提供了互斥锁的功能。 而PriorityLock则在基本的互斥锁基础上增加了一层优先级判断。在默认情况下,所有线程平等竞争锁,但PriorityLock...
2. **同步机制**:Java提供了多种同步机制来控制多线程对共享资源的访问,如synchronized关键字、wait()和notify()方法、Lock接口(包括ReentrantLock可重入锁)以及Semaphore信号量等。学习如何避免并发环境下的...
- `ReentrantLock`是可重入锁,提供了更细粒度的控制,如公平锁、非公平锁、读写锁等。 7. **响应式编程** - 响应式编程是一种编程范式,适用于处理高并发和流式数据。Java中的Reactor项目提供了响应式编程的支持...
- **Lock接口与ReentrantLock**:提供更灵活的线程同步机制,如公平锁、非公平锁、可重入锁、读写锁等。 4. **线程优先级** Java线程有10个优先级,从MIN_PRIORITY(1)到MAX_PRIORITY(10),默认是NORM_PRIORITY(5)...
例如,`Thread`类的内部实现、`synchronized`关键字如何实现内存同步、`ReentrantLock`如何实现可重入和公平性等。你可以通过反编译JDK源码或查看OpenJDK源码库进行学习。 7. **实际应用** 多线程和同步在实际项目...