zoukankan      html  css  js  c++  java
  • ConCurrent并发包

    synchronized的缺陷

     
    我们知道,可以利用synchronized关键字来实现共享资源的互斥访问。Java 5在java.util.concurrent.locks包下提供了另一种来实现线程的同步访问,那就是Lock。既然有了synchronized来实现线程同步,Java为什么还需要提供Lock呢?
    synchronized是Java的一个关键字,当我们使用synchronized来修饰方法或代码块时,线程必须先获得对应的锁才能执行该段代码。而其他线程只能一直等待,直到当前线程释放锁并获得对应的锁才能进入该段代码。这里获取锁的线程释放锁只会有两种情况:
    • 获取锁的线程执行完该段代码,线程会释放占有的锁;
    • 线程执行发生异常,此时JVM会让线程自动释放锁。
    那么如果这个占有锁的线程由于等待IO或其他原因(比如调用sleep方法)被阻塞,但是还没有释放锁,那么其他线程只能干巴巴的等着,试想这多么影响程序的执行效率。
    当多个线程同时读写文件是,我们知道读操作和写操作会发生冲突,写操作和写操作也会发生冲突,但是读操作和读操作之间不会冲突。synchronized关键字对一段代码加锁,所有的线程必须先获得对应的锁才有该代码段的执行权限。如果多个线程同时进行读操作时,使用synchronized关键字会导致在任何时刻只有一个线程读,其他线程等待,大大降低执行效率。
     
    Lock可以对以上种种情况作优化,提供更好的执行效率。另外,Lock方便了对锁的管理,可以自由的加锁和释放锁,还可以判断有没有成功获取锁。但是在使用Lock时要注意,Lock需要开发者手动去释放锁,如果没有主动释放锁,就要可能导致死锁出现。建议在finally语句块中释放Lock锁。
     
     
     

    concurrent.locks包下常用类

     
    1. Lock
     
    首先要说明的是Lock,它是一个接口:
    [java] view plain copy
     
    1. public interface Lock {  
    2.     void lock();  
    3.     void lockInterruptibly() throws InterruptedException;  
    4.     boolean tryLock();  
    5.     boolean tryLock(long time, TimeUnit unit) throws InterruptedException;  
    6.     void unlock();  
    7.     Condition newCondition();  
    8. }  
    • lock()方法用来获取锁。
    • tryLock()尝试获取锁,如果成功则返回true,失败返回false(其他线程已占有锁)。这个方法会立即返回,在拿不到锁时也不会等待。
    • tryLock(long time, TimeUnit unit)方法和tryLock()方法类似,只不过在拿不到锁时等待一定的时间,如果超过等待时间还拿不到锁就返回false。
    • lockInterruptibly()方法比较特殊,当通过这个方法获取锁时,如果该线程正在等待获取锁,则它能够响应中断。也就是说,当两个线程同时通过lockInterruptibly()获取某个锁时,假如线程A获得了锁,而线程B仍在等待获取锁,那么对线程B调用interrupt()方法可以中断B的等待过程。
    [java] view plain copy
     
    1. // lock()的使用  
    2. Lock lock = ...;  
    3. lock.lock();  
    4. try{  
    5.     //处理任务  
    6. }catch(Exception ex){  
    7.        
    8. }finally{  
    9.     lock.unlock();   //释放锁  
    10. }  
    [java] view plain copy
     
    1. // tryLock()的使用  
    2. Lock lock = ...;  
    3. if(lock.tryLock()) {  
    4.      try{  
    5.          //处理任务  
    6.      }catch(Exception ex){  
    7.            
    8.      }finally{  
    9.          lock.unlock();   //释放锁  
    10.      }   
    11. }else {  
    12.     //如果不能获取锁,则直接做其他事情  
    13. }  
    [java] view plain copy
     
    1. // lockInterruptibly()的使用  
    2. public void method() throws InterruptedException {  
    3.     lock.lockInterruptibly();  
    4.     try {    
    5.      //.....  
    6.     }  
    7.     finally {  
    8.         lock.unlock();  
    9.     }    
    10. }  
    使用synchronized关键字,当线程处于等待锁的状态时,是无法被中断的,只能一直等待。
     
    2.ReentrantLock
     
    ReentrantLock是可重入锁。如果所具备可重入性,则称为可重入锁,synchronized可ReentrantLock都是可重入锁。可重入锁也叫递归锁,当一个线程已经获得该代码块的锁时,再次进入该代码块不必重新申请锁,可以直接执行。
     
    例1, lock()的使用方法:
    [java] view plain copy
     
    1. public class Test {  
    2.     private ArrayList<Integer> arrayList = new ArrayList<Integer>();  
    3.     private Lock lock = new ReentrantLock();    //注意这个地方  
    4.     public static void main(String[] args)  {  
    5.         final Test test = new Test();  
    6.            
    7.         new Thread(){  
    8.             public void run() {  
    9.                 test.insert(Thread.currentThread());  
    10.             };  
    11.         }.start();  
    12.            
    13.         new Thread(){  
    14.             public void run() {  
    15.                 test.insert(Thread.currentThread());  
    16.             };  
    17.         }.start();  
    18.     }    
    19.        
    20.     public void insert(Thread thread) {  
    21.         lock.lock();  
    22.         try {  
    23.             System.out.println(thread.getName()+"得到了锁");  
    24.             for(int i=0;i<5;i++) {  
    25.                 arrayList.add(i);  
    26.             }  
    27.         } catch (Exception e) {  
    28.             // TODO: handle exception  
    29.         }finally {  
    30.             System.out.println(thread.getName()+"释放了锁");  
    31.             lock.unlock();  
    32.         }  
    33.     }  
    34. }  
    例2, lockInterruptibly()响应中断的使用方法:
    [java] view plain copy
     
    1. public class Test {  
    2.     private Lock lock = new ReentrantLock();     
    3.     public static void main(String[] args)  {  
    4.         Test test = new Test();  
    5.         MyThread thread1 = new MyThread(test);  
    6.         MyThread thread2 = new MyThread(test);  
    7.         thread1.start();  
    8.         thread2.start();  
    9.            
    10.         try {  
    11.             Thread.sleep(2000);  
    12.         } catch (InterruptedException e) {  
    13.             e.printStackTrace();  
    14.         }  
    15.         thread2.interrupt();  
    16.     }    
    17.        
    18.     public void insert(Thread thread) throws InterruptedException{  
    19.         lock.lockInterruptibly();   //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出  
    20.         try {    
    21.             System.out.println(thread.getName()+"得到了锁");  
    22.             long startTime = System.currentTimeMillis();  
    23.             for(    ;     ;) {  
    24.                 if(System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)  
    25.                     break;  
    26.                 //插入数据  
    27.             }  
    28.         }  
    29.         finally {  
    30.             System.out.println(Thread.currentThread().getName()+"执行finally");  
    31.             lock.unlock();  
    32.             System.out.println(thread.getName()+"释放了锁");  
    33.         }    
    34.     }  
    35. }  
    36.    
    37. class MyThread extends Thread {  
    38.     private Test test = null;  
    39.     public MyThread(Test test) {  
    40.         this.test = test;  
    41.     }  
    42.     @Override  
    43.     public void run() {  
    44.            
    45.         try {  
    46.             test.insert(Thread.currentThread());  
    47.         } catch (InterruptedException e) {  
    48.             System.out.println(Thread.currentThread().getName()+"被中断");  
    49.         }  
    50.     }  
    51. }  

    3. ReadWriteLock
     
    ReadWriteLock也是一个接口,它只定义了两个方法:
    [java] view plain copy
     
    1. public interface ReadWriteLock {  
    2.     /** 
    3.      * Returns the lock used for reading. 
    4.      */  
    5.     Lock readLock();  
    6.    
    7.     /** 
    8.      * Returns the lock used for writing. 
    9.      */  
    10.     Lock writeLock();  
    11. }  
    readLock()用来获取读锁,writeLock()用来获取写锁。也就是将文件的读写操作分开,分成两个锁来分配给线程,从而使多个线程可以同时进行读操作。ReentrantReadWriteLock是它的实现类。
     
    [java] view plain copy
     
    1. public class Test {  
    2.     private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();  
    3.        
    4.     public static void main(String[] args)  {  
    5.         final Test test = new Test();  
    6.            
    7.         new Thread(){  
    8.             public void run() {  
    9.                 test.get(Thread.currentThread());  
    10.             };  
    11.         }.start();  
    12.            
    13.         new Thread(){  
    14.             public void run() {  
    15.                 test.get(Thread.currentThread());  
    16.             };  
    17.         }.start();  
    18.            
    19.     }    
    20.        
    21.     public void get(Thread thread) {  
    22.         rwl.readLock().lock();  
    23.         try {  
    24.             long start = System.currentTimeMillis();  
    25.                
    26.             while(System.currentTimeMillis() - start <= 1) {  
    27.                 System.out.println(thread.getName()+"正在进行读操作");  
    28.             }  
    29.             System.out.println(thread.getName()+"读操作完毕");  
    30.         } finally {  
    31.             rwl.readLock().unlock();  
    32.         }  
    33.     }  
    34. }  
  • 相关阅读:
    深度解析正则表达式exec和match两者使用的异同以及要注意的地方
    CSS中有关水平居中和垂直居中的解决办法
    Ubunut16.04 安装 Mahout
    正则表达式常用方法
    python字符串判断
    python list
    python一些包
    数据科学中的R和Python: 30个免费数据资源网站
    simple vimrc for python
    python的一些方法
  • 原文地址:https://www.cnblogs.com/panxuejun/p/8622596.html
Copyright © 2011-2022 走看看