java并发编程系列之Lock的使用

Jdk1.5中,在Java.util.concurrent.locks包下,有一组实现线程同步的接口和类,说到线程的同步,很多立马就会想到synchronized关键字,这是java内置的关键字,用来处理线程同步的,但这个关键字有很多的缺陷,使用起来也不是很方便和直观,所以就出现了Lock,下面,我们就来对比着讲解Lock。

synchronized关键字:

该关键字在使用的过程中会有如下几个问题:

1、不可控性,无法做到随心的加锁和释放锁

2、效率比较低下,比如我们现在并发的读两个文件,读与读之间是互不影响的,但如果给这个读的对象使用synchronized来实现同步的话,那么只要有一个线程进入了,那么其他的线程都要等待。

3、无法知道线程是否获取到了锁

以上问题,Lock都可以很好的解决,并且jdk1.5还提供了各种锁,例如读写锁,但有一点需要注意,使用synchronized关键时,无须手动释放锁,但使用Lock必须手动释放锁。下面我们就来学习一下Lock锁。

Lock是一个上层的接口,其原型如下,总共提供了6个方法:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public interface Lock {  
  2.     // 用来获取锁,如果锁已经被其他线程获取,则一直等待,直到获取到锁  
  3. void lock();  
  4. // 该方法获取锁时,可以响应中断,比如现在有两个线程,一个已经获取到了锁,另一个线程调用这个方法正在等待锁,但是此刻又不想让这个线程一直在这死等,可以通过调用线程的Thread.interrupted()方法,来中断线程的等待过程  
  5.     void lockInterruptibly() throws InterruptedException;  
  6.     // tryLock方法会返回bool值,该方法会尝试着获取锁,如果获取到锁,就返回true,如果没有获取到锁,就返回false,但是该方法会立刻返回,而不会一直等待  
  7. boolean tryLock();  
  8. // 这个方法和上面的tryLock差不多是一样的,只是会尝试指定的时间,如果在指定的时间内拿到了锁,则会返回true,如果在指定的时间内没有拿到锁,则会返回false  
  9. boolean tryLock(long time, TimeUnit unit) throws InterruptedException;  
  10. // 释放锁  
  11. void unlock();  
  12. // 实现线程通信,相当于wait和notify,后面会单独讲解  
  13.     Condition newCondition();  
  14. }  

那么这几个方法该如何使用了?前面我们说到,使用Lock是需要手动释放锁的,但是如果程序中抛出了异常,那么就无法做到释放锁,有可能引起死锁,所以我们在使用Lock的时候,有一种固定的格式,如下:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // 下面这段代码摘自官方文档  
  2. Lock l = ...;  
  3.      l.lock();  
  4.      try {  
  5.          // access the resource protected by this lock  
  6.      } finally {// 必须使用try,最后在finally里面释放锁  
  7.          l.unlock();  
  8.      }  
下面我们来看一个简单的例子,代码如下:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 描述:Lock使用 
  3.  */  
  4. public class LockDemo {  
  5.     // new一个锁对象,注意此处必须声明成类对象,保持只有一把锁,ReentrantLock是Lock的唯一实现类  
  6.     Lock lock = new ReentrantLock();  
  7.     public void readFile(String fileMessage){  
  8.         lock.lock();// 上锁  
  9.         try{  
  10.             System.out.println(Thread.currentThread().getName()+"得到了锁,正在读取文件……");  
  11.             for(int i=0; i<fileMessage.length(); i++){  
  12.                 System.out.print(fileMessage.charAt(i));  
  13.             }  
  14.             System.out.println();  
  15.             System.out.println("文件读取完毕!");  
  16.         }finally{  
  17.             System.out.println(Thread.currentThread().getName()+"释放了锁!");  
  18.             lock.unlock();  
  19.         }  
  20.     }  
  21.       
  22.     public void demo(final String fileMessage){  
  23.         // 创建若干个线程  
  24.         ExecutorService service = Executors.newCachedThreadPool();  
  25.         // 提交20个任务  
  26.         for(int i=0; i<20; i++){  
  27.             service.execute(new Runnable() {  
  28.                 @Override  
  29.                 public void run() {  
  30.                     readFile(fileMessage);  
  31.                     try {  
  32.                         Thread.sleep(20);  
  33.                     } catch (InterruptedException e) {  
  34.                         e.printStackTrace();  
  35.                     }  
  36.                 }  
  37.             });  
  38.         }  
  39.     // 释放线程池中的线程  
  40.         service.shutdown();  
  41.     }  
  42. }  

我们先把锁的那两行代码注释掉,看下效果如何:


然后我们把锁的代码加上,看下效果如何:


如果我们把上面的readFile方法前面加上synchronized关键字,然后把锁去掉,效果是一样的。

tryLock锁的使用和Lock锁的使用类似,下面把示例代码贴出来,就不做过多的说明了,代码如下:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 描述:TryLock使用 
  3.  */  
  4. public class TryLockDemo {  
  5.     // new一个锁对象  
  6.     Lock lock = new ReentrantLock();  
  7.     public void readFile(String fileMessage){  
  8.         if(lock.tryLock()){  
  9.             try{  
  10.                 System.out.println(Thread.currentThread().getName()+"得到了锁,正在读取文件……");  
  11.                 System.out.println("文件读取完毕!");  
  12.             }finally{  
  13.                 System.out.println(Thread.currentThread().getName()+"释放了锁!");  
  14.                 lock.unlock();  
  15.             }  
  16.         }else{  
  17.             System.out.println(Thread.currentThread().getName()+"获取锁失败!");  
  18.         }  
  19.     }  
  20.       
  21.     public void demo(final String fileMessage){  
  22.         // 创建若干个线程  
  23.         ExecutorService service = Executors.newCachedThreadPool();  
  24.         // 提交200个任务  
  25.         for(int i=0; i<200; i++){  
  26.             service.execute(new Runnable() {  
  27.                 @Override  
  28.                 public void run() {  
  29.                     readFile(fileMessage);  
  30.                 }  
  31.             });  
  32.         }  
  33.         // 释放线程池中的线程  
  34.         service.shutdown();  
  35.     }  
  36. }  

测试效果如下:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值