zoukankan      html  css  js  c++  java
  • 多线程(三)---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()+":已经结束了写操作"));
            }
        }
    
    }
  • 相关阅读:
    [JZOJ3386] 守卫者的挑战
    [JZOJ3385] 黑魔法师之门
    [JZOJ3383] 太鼓达人
    [JZOJ3382] 七夕祭
    NOIP模拟测试on 2019.9.27
    数据结构测试2 on 2019.9.25
    数据结构测试1 on 2019.9.24
    P2047 [NOI2007]社交网络
    P2286 [HNOI2004]宠物收养场
    P1342 请柬 建反图+dijkstra
  • 原文地址:https://www.cnblogs.com/qqwhsj/p/10637486.html
Copyright © 2011-2022 走看看