Java 5 引入的 Concurrent 并发库软件包中,提供了 ReentrantLock 可重入同步锁,用来替代 synchronized 关键字原语,并可提供更好的性能,以及更强大的功能。使用方法也很简单:
public final ReentrantLock lock=new ReentrantLock();
……
try {
lock.lock();
// 进入同步内容
….
} finally {
lock.unlock(); // 必须在 finally 块中解锁,否则一旦出现异常,执行不到解锁,则一直锁住了。
}
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原语来加锁,如下:
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个线程,一个线程去写,一个线程去读。
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来试验下,我们有意先去“写”,然后让“读”等待,“写”的时间是无穷的,就看“读”能不能放弃了。
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吧,可中断缓存。
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做响应的修改
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()中断,并且有效处理了这个“异常”。
[http://hi.baidu.com/cyberniuniu/item/7fdba2fbe9373b733d198b34]
分类目录
- arch/management (17)
- computer (38)
- java/j2ee (305)
- lnmpa (237)
- mac/iphone/ipad/android (11)
- mysql/oracle/postgresql (126)
- os/software (74)
- other (518)
- python (6)
- redis/memcached/mongo (31)
- sitebuild (143)
随便看看
标签云
程序员 创业 人生箴言 eclipse 快捷键 术语 索引 unix命令 vim wordpress java学习笔记 环境变量 oracle内置函数 index 人生 数据类型 nohup tuxedo mysql学习笔记 MS-DOS命令 servlet spring 职场进阶 职业进阶 服务器选购 服务器选型 apache JPA MongoDB 注解 tomcat 子女教育 jquery maven JVM aix命令 网络营销 java异常 seo 人生规划 关键字 css 网络推广 struts 系统优化 成长 frame iframe bluehost jdbc select 我的信仰 oracle函数 cookie HashMap 站长工具 乱码 ArrayList secureCRT jsp session tail find halt 事务 oracle单记录函数 算法 URL window table javascript操作表单元素 String 字符串处理 健康 http 域名 情感 more google A记录 域名解析 netstat 弹出对话框 弹出窗口 框架集 框架 excel 字符串 javascript函数 showModalDialog nginx number 数组 sql frameset 开源程序 java数组 软件 oracle服务友情链接
收藏链接