首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

ReentrantLock(1)

2013-03-10 
ReentrantLock(一)synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中

ReentrantLock(一)

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();????
?????
??? }????
}???

这次“读”线程接收到了lock.lockInterruptibly()中断,并且有效处理了这个“异常”。好奇的读者,肯定要探个究竟,为什么ReentrantLock能做到这点,接下来请查看ReentrantLock(二)

热点排行