多线程(三)---Lock

一、Lock的基本介绍

   1.Lock本身是一个接口,接口中含有四个抽象方,且不是Java内置的。

   2.分别是lock(),unlock(),trylock()以及lockInterruptibly(){下方有详细介绍}。

   3.Lock是一个操作麻烦(对比Synchronized来说),但是功能强大的锁。

   lock的源码:

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

     透过源码我们可以看到Lock本身是一个包含有四个抽象方法的接口。

二、Synchronized的优点与缺点

      Synchronized的优点:操作比较简单不需要手动释放锁,自带异常处理机制。

      Synchronized的缺点:Synchronized功能单一,无法做比较细节的操作。Synchronized采用悲观锁机制,在保护了安全的同时,牺牲了效率。

三、Lock的四种方法

      1.因为Lock只是一个接口,而实现了Lock接口的类只有ReentrantLock。所以我们通过子类向上传递的方式得到Lock。

      1.lock():

               lock本身只是单纯的一个锁,当调用lock()时,如果资源处于被释放状态,则线程锁住该资源;否则线程进入等待状态等候资源的被释放。值的注意的是,Lock本身不具备异常机制,所以我们需要自行作出异常处理机制。

public class LockTest {
    static Lock lock = new ReentrantLock();
    public static void main(String[]args){
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        LockTest.instert(Thread.currentThread());
                    }
                }
        ).start();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        LockTest.instert(Thread.currentThread());
                    }
                }
        ).start();
    }

    public static void instert(Thread thread){
        lock.lock();
        try{
            System.out.println(Thread.currentThread()+":获取了锁");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            System.out.println(Thread.currentThread()+":释放了锁");
            lock.unlock();   
        }
    }

}

      2.unlock():

          当调用该方法时,会释放当下资源。与Synchronized不同,Lock是需要手动调用方法来释放锁的(很重要),不然将陷入死锁状态。所以我们常常在异常处理中的finally模块来调用unlock()。

      3.trylock():

          线程尝试获取资源,如果可以获得该资源,则会返回true,否则会返回false;trylock的重载方法中,可以设置时间以及时间格式来完成在一段时间内尝试获取资源,如果有则返回true,否则返回false;

这是使用trylock方法:

public class LockTest {
    static Lock lock = new ReentrantLock();
    public static void main(String[]args) {
        new Thread (
                new Runnable() {
                    @Override
                    public void run(){
                        LockTest.instert(Thread.currentThread());
                    }
                }
        ).start();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        LockTest.instert(Thread.currentThread());
                    }
                }
        ).start();
    }

    public static void instert(Thread thread){
        if(lock.tryLock()) {
            try {
                System.out.println(Thread.currentThread() + ":获取了锁");
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread() + ":释放了锁");
                lock.unlock();
            }
        }else{
            System.out.println(Thread.currentThread()+":没能获得锁");
        }
    }

}
trylock带参数的实现:由于带参方法作出了InterrupedException,所以调用该方法的方法都应该抛出该异常,但是重写的Run方法无法抛出异常所以需要手动在run中调用trycatch方式抛出异常
public class LockTest {
    static Lock lock = new ReentrantLock();
    public static void main(String[]args) {
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        try{
                            LockTest.instert(Thread.currentThread());
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        try{
                            LockTest.instert(Thread.currentThread());
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
    }

    public static void instert(Thread thread) throws InterruptedException{
        if(lock.tryLock((long)2000,TimeUnit.MILLISECONDS)){
            try {
                System.out.println(Thread.currentThread() + ":获取了锁");
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread() + ":释放了锁");
                lock.unlock();
            }
        }else{
            System.out.println(Thread.currentThread()+":没能获得锁");
        }
    }

}

4.lockInterruptibly():

         lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。

        这就是Lock锁的可中断性,是Synchronized不具备的:

public class LockTest {
    static Lock lock = new ReentrantLock();
    public static void main(String[]args) {
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        try{
                            LockTest.instert(Thread.currentThread());
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
        ).start();
        Thread thread1 = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        try{
                            LockTest.instert(Thread.currentThread());
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
        );
        thread1.start();
        thread1.interrupt();
        System.out.println(thread1.isAlive());

    }

    public static void instert(Thread thread) throws InterruptedException{

//        if(lock.tryLock((long)2000,TimeUnit.MILLISECONDS)){          //2000毫秒的尝试
//        if(lock.tryLock()){        //trylock尝试一次
//      lock.lock();          //调用锁方法
          lock.lockInterruptibly();
            try {
                System.out.println(Thread.currentThread() + ":获取了锁");
                Thread.sleep(10000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread() + ":释放了锁");
                lock.unlock();
            }
//        }else{
//            System.out.println(Thread.currentThread()+":没能获得锁");
//        }
    }

}

四、ReadWriteLock类:

        这个类也是一个接口,该接口只定义了writeLock与readLock两个抽象方法,而且这两个方法最后都会返回一个Lock。源码如下:

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing
     */
    Lock writeLock();
}

   调用ReentrantReadWriteLock中readLock会返回ReentrantReadWriteLock.ReadLock类,该类中依然拥有trylock,lock,newCondition,unlock等方法。

   调用ReentrantReadWriteLock中readLock会返回ReentrantwriteWriteLock.WriteLock类,该类中依然拥有trylock,lock,newCondition,unlock等方法。

   当两个都是读取时,锁允许多个线程使用,有一个是写线程时,则进入的线程会锁住。

public class ReadWrite {
    static ReentrantReadWriteLock rl =new ReentrantReadWriteLock();
    public static void main(String[]args){
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        ReadWrite.insert(Thread.currentThread());
                    }
                }
        ).start();
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        ReadWrite.insert(Thread.currentThread());
                    }
                }
        ).start();

    }
    public static void insert(Thread thread1){
         rl.writeLock().lock();
//         rl.readLock().lock();
        try{
            long start = System.currentTimeMillis();
            while(System.currentTimeMillis()-start<=300) {
                System.out.println(Thread.currentThread().getName() + "正在进行写操作");
                Thread.sleep(10);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            rl.writeLock().unlock();
//            rl.readLock().unlock();
            System.out.println((Thread.currentThread()+":已经结束了写操作"));
        }
    }

}
原文地址:https://www.cnblogs.com/qqwhsj/p/10637486.html