java多线程之并发Lock

版权声明:转载请注明:beOkWithAnything总结 https://blog.csdn.net/swq463/article/details/85224629

Lock出现原因

  • synchronized的缺陷:  如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,如果这个获取锁的线程由于要等待IO或者其他原因被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待:如果多个线程都只是进行读操作,当一个线程在进行读操作时,其他线程只能等待无法进行读操作。当有多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作会发生冲突现象,但是读操作和读操作不会发生冲突现象,很影响程序执行效率。因此需要一种可以不让等待的线程一直无期限地等待下去的机制(比如只等待一定的时间或者能够响应中断)
  • 另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的

Lock和synchronized的区别

  • synchronized 是 Java语言的关键字,因此是内置特性。Lock是一个,通过这个类可以实现同步访问
  • 采用synchronized 不需要用户去手动释放锁。而Lock 则必须要用户去手动释放锁

java.util.concurrent.locks包的探索

Lock接口

public interface Lock { // Lock是一个接口
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

lock( )

lock( ) 方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。

采用Lock类就必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用 Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在 finally块 中进行,以保证锁一定被被释放,防止死锁的发生。

Lock lock = new ReentrantLock();
lock.lock();
try{
    //处理任务
}catch(Exception ex){
     
}finally{
    lock.unlock();   //释放锁
}

tryLock( )

tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false。也就说这个方法无论如何都会立即返回在拿不到锁时不会一直在那等待

tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false

Lock lock = ...;
if(lock.tryLock()) {
     try{
         //处理任务
     }catch(Exception ex){
         
     }finally{
         lock.unlock();   //释放锁
     } 
}else {
    //如果不能获取锁,则直接做其他事情
}

lockInterruptibly( )

lockInterruptibly() 方法比较特殊,当通过这个方法去获取锁时,正在等待获取锁的这个线程能够响应中断,即用lockinterruptibly( )方法去获取锁而未成功时可以用interrupt()方法将其等待中断。比如,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。

lock.lockInterruptibly( )必须放在try块中或者在调用lockInterruptibly()的方法外声明 抛出InterruptedException

  • 当一个线程获取了锁之后,是不会被interrupt() 方法中断的。因为单独调用interrupt()方法不能中断正在运行过程中的线程,只能中断阻塞过程中的线程。

ReentrantLock类

ReentrantLock,意思是“可重入锁”,ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。

public class Test {
    private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    private Lock lock = new ReentrantLock();    //在这个地方声明Lock对象

    public static void main (String[] args)  {
        final Test test = new Test();
         
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
         
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
    }  
     
    public void insert(Thread thread) {
        /* Lock lock = new ReentrantLock(); 
        如果这句写在方法里,那么每个线程都会创建一个Lock对象,
        每个线程都会获取到test对象的锁,无法实现同步 */
        lock.lock(); // 在这里调用lock()方法获取锁
        try {
            System.out.println(thread.getName()+"得到了锁");
            for(int i=0;i<5;i++) {
                arrayList.add(i);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }finally {
            System.out.println(thread.getName()+"释放了锁");
            lock.unlock();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/swq463/article/details/85224629