一直以来都想好好研究下ReentrantLock,她的独到魅力令我屡试不爽,无奈网上实在是没有太多的资料可以参考,于是自己开始深入研究它的内部实现机制,经过数天的研究,终于有点心得体会升华了,记录之……
synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候
下面细细道来……
我们定义一个读程序、定义一个写程序
下面是测试main方法
测试发现,执行后显示
发现尝试中断的时候,并没有中断,因为线程得不到锁,就一直等待,因为写线程耗时非常长,几乎是无穷尽的,肯定超过一个小时(暂且,粗估),
ReentrantLock实现了,reader类中断自己,然后用户可以根据自己的需要进行异常操作。
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 implements IBuffer {
private Object lock;
public Buffer() {
this.lock = this;
}
@Override
public void write() {
// TODO Auto-generated method stub
synchronized(lock){
long startTime = System.currentTimeMillis();
System.out.println("开始往这个buff写入数据.....");
for(;;){
if(System.currentTimeMillis()-startTime>=Integer.MAX_VALUE){
break;
}
}
System.out.println("终于写完了");
}
}
@Override
public void read() throws InterruptedException {
// TODO Auto-generated method stub
synchronized(lock){
System.out.println("从这个buff读取数据");
}
}
}
我们定义一个读程序、定义一个写程序
public class Writer extends Thread {
private IBuffer buff;
public Writer(IBuffer buff){
this.buff = buff;
}
public void run(){
buff.write();
}
}
class Reader extends Thread{
private IBuffer buff;
public Reader(IBuffer buff){
this.buff = buff;
}
public void run(){
try {
buff.read();//可以收到中断的异常,从而有效退出
} catch (InterruptedException e) {
System.out.println("我不读了" );
}
System.out.println("读结束" );
}
}
下面是测试main方法
public class TestRenntrantLock {
public static boolean useSynchronized = true;
public static void main(String [] args){
IBuffer buff = null;
if(useSynchronized){
buff =new Buffer();
}
else{
buff = new BufferInterruptibly();
}
final Writer write = new Writer(buff);
final Reader reader =new Reader(buff);
write.start();
reader.start();
new Thread (new Runnable() {
public void run(){
long startTime =System.currentTimeMillis();
for(;;){
if(System.currentTimeMillis()-startTime>9000){
System.out.println("不等了,尝试中断");
reader.interrupt();
break;
}
}
}
}
).start();
}
}
测试发现,执行后显示
开始往这个buff写入数据.....
不等了,尝试中断
发现尝试中断的时候,并没有中断,因为线程得不到锁,就一直等待,因为写线程耗时非常长,几乎是无穷尽的,肯定超过一个小时(暂且,粗估),
ReentrantLock给了一种机制让我们来响应中断,让“读”能伸能屈,勇敢放弃 对这个锁的等待。我们来改写Buffer这个类,就叫BufferInterruptibly吧,可中断缓存。
import java.util.concurrent.locks.ReentrantLock;
public class BufferInterruptibly implements IBuffer {
private ReentrantLock lock = new ReentrantLock();//参数默认false,不公平锁
@Override
public void write() {
// TODO Auto-generated method stub
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();
}
}
@Override
public void read() throws InterruptedException {
// TODO Auto-generated method stub
lock.lockInterruptibly(); //可以响应中断
try {
System.out.println("从这个buffer读取数据");
}finally {
lock.unlock();
}
}
}
ReentrantLock实现了,reader类中断自己,然后用户可以根据自己的需要进行异常操作。